MySQL vs Firebird: accessing query columns in PHP with PDO - php

From what I understood, using PDO should be the same result regardless of what DB I am using. I tested this in the following code, which I have connected to two separate DB's.
$sth = $pdo->query('SELECT * FROM posts');
while($result = $sth->fetch(PDO::FETCH_BOTH)){
echo $result[1] . '<br>';
};
MySQL DB:
$dsn = 'mysql:host=' . $server . ';dbname=' . $dbname;
$pdo = new PDO($dsn, $username, $password);
Firebird DB:
$dsn = "firebird:dbname=" . $server . ":" . $dbname;
$pdo = new PDO($dsn, $username, $password);
The MySQL connection worked fine, while the Firebird connection worked only with numbered Arrays - FETCH_NUM, and FETCH_BOTH when using index positions. Is this how its supposed to be or am I doing something wrong with my Firebird connection? I will need to work with the Firebird DB in the future, so this really frustrates me. Thank you for all comments.

In Firebird, by default, mainly from historical reasons, unless you use double quotes on object names (field names, tables, etc...), they are uppercase-d and stored internally in uppercase.
Accordingly, the column names you receive in result set are in uppercase, so you should address them in upper-case like $row['FIELD_NAME'].
Alternatively, in PHP, PDO driver have a special flag used on connection, PDO::ATTR_CASE => PDO::CASE_LOWER/NATURAL/UPPER that adjust the needed case internally for you.
For example:
$source = $d['kind'].':'.'dbname='.$d['host'].':'.$d['base'].';charset='.$d['charset'];
$options = $d['options'] + [
\PDO::ATTR_CASE => \PDO::CASE_LOWER,
\PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION
];
$connection = new \PDO($source, $d['user'], $d['password'], $options);
Firebird is not alone doing this. Oracle also stores by default metadata in uppercase. Some DBMSes have options, others in lower-case by default.

Related

Connect to MySQL database in PHP

I'm trying to build a blog website.
It is deployed on Heroku and it is supposed to connect to a MySQL database. The info required to login to my database is stored in an environment variable on Heroku, and looks like this (These are fake credentials of course):
mysql://g46w916ds134b8:639f463e#us-cdbr-east-03.cleardb.net/heroku_45fab1d19h35yetf?reconnect=true
It contains the DB name, the user, the password and the host.
Is there a way to use this one string directly in my PHP code to connect to the database? I checked MySQLi and PDO documentation, and it seems like they only accept DSN/user/password or Host/user/password/DBname format.
This is a url after all, so you can use parse_url function to extract data.
// Connection string from environmental variable in heroku
$connectionStringHerokuEnv = 'mysql://g46w916ds134b8:639f463e#us-cdbr-east-03.cleardb.net/heroku_45fab1d19h35yetf?reconnect=true';
$parsed = parse_url($connectionStringHerokuEnv);
$dbname = ltrim($parsed['path']. '/'); // PATH has prepended / at the beginning, it needs to be removed
// Connecting to the database
$conn = new PDO("{$parsed['scheme']}:host={$parsed};$dbname={$dbname};charset=utf8mb4", $parsed['user'], $parsed['pass'], [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
For database connection you should always use PDO and not mysqli driver. PDO allows you to connect to almost any database, without rewriting code in 85% of cases.
dont forget options [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION], this will allow you to catch any errors and handle them accordingly to application needs.
PDO accept this connection string driver: host=DATABASE_HOST;dbname=DATABASE_NAME; charset=DEFAULT_CHARSET(use utf8 whenever you can)
Learn more on parse_url: https://www.php.net/manual/en/function.parse-url
Learn more on PDO:
https://www.php.net/manual/en/class.pdo.php
<?php
$str = "mysql://g46w916ds134b8:639f463e#us-cdbr-east-03.cleardb.net/heroku_45fab1d19h35yetf?reconnect=true";
// If I correctly understanded 'mysql://login:passwd#host/dbname?some_params'
// data parsing from input string
$sp = explode('/', $str);
$sp1 = explode('#', $sp[2]);
$first_part_sp = explode(':', $sp1[0]);
$login = $first_part_sp[0];
$passwd = $first_part_sp[1];
$host = $sp1[1];
$dbname = explode('?', $sp[3])[0];
$connect_str = "mysql:host=$host;dbname=$dbname";
echo $connect_str." ".$login." ".$passwd;
// database access
$pdo = new PDO($connect_str, $user, $passwd);
?>

Different solution to `Cannot execute queries while other unbuffered queries are active`

I've just migrated from MySQL to newer MariaDB and all my websites are now showing:
Cannot execute queries while other unbuffered queries are active.
Consider using PDOStatement::fetchAll(). Alternatively, if your code
is only ever going to run against mysql, you may enable query
buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute.
I googled this error and tried doing what people suggested.
So I changed my code to use PDO's closeCursor().
I tried using PDO::MYSQL_ATTR_USE_BUFFERED_QUERY and nothing works.
And here's how my constructor looked:
$pdo = new PDO('mysql:host=' . $host . ';dbname=' . $db . ';port=' . $port, $user, $pass,
array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8;SET SESSION time_zone="system"',
PDO::MYSQL_ATTR_LOCAL_INFILE => true
));
I changed it to
$pdo = new PDO('mysql:host=' . $host . ';dbname=' . $db . ';port=' . $port, $user, $pass,
array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8, SESSION time_zone="system"',
PDO::MYSQL_ATTR_LOCAL_INFILE => true
));
and it does work now.
I am posting my solution here because all other places have "wrong" ones.
So the difference is instead of having
'SET NAMES utf8;SET SESSION time_zone="system"'
in PDO::MYSQL_ATTR_INIT_COMMAND I have:
'SET NAMES utf8, SESSION time_zone="system"'
and everything's fine now.

I Can't Reach A DB Using PDO

I'm following a tutorial that is teaching PDO but I'm stuck at a very early point.
Referring to the code below I have diagnosed the problem down to the DB selected.
When I run print_r($query); there is no output and initallally I thought the problem was that the script wasn't connecting to the MySql server at all but then I learned if I change anything in host, user or pass I get an error message, but no matter what I change related to the database nothing happens and no error messages are displayed.
<?php
error_reporting(E_ALL);
$config['db'] = array(
'host' => 'xxxx',
'user' => 'xxxx',
'pass' => 'xxxx',
'database' => 'xxxx'
);
$db = new PDO('mysql:host=' . $config['db']['host'] . ';database=' . $config['db']['database'],$config['db']['user'], $config['db']['pass']);
$query = $db->query("SELECT `subscribers`.`first_name` FROM `subscribers`");
print_r($query);
echo 'Anything';
?>
If anyone could show me what Im doing wrong I'd be most appreciative and I thank you in advance.
BTW, I am SURE that SELECT subscribers.first_name FROM subscribers is correct as this works when I insert it into the mysql tab within php MyAdmin
I believe the DSN parameter for database name is called dbname, not database.
Try this:
$db = new PDO('mysql:host=' . $config['db']['host'] . ';dbname=' . $config['db']['database'],$config['db']['user'], $config['db']['pass']);
After creating a connection with database you need to create a statement, set query, bind values(optional), execute the query and fetch the result. In your case:
$db = new PDO('mysql:host=' . $config['db']['host'] . ';database=' . $config['db'] ['database'],$config['db']['user'], $config['db']['pass']);
$query = $db->prepare("SELECT `subscribers`.`first_name` FROM `subscribers`");
$query->execute();
$result = $query->fetchAll();
var_dump($result);

How do I select a MySQL database to use with PDO in PHP?

I want to select a MySQL database to use after a PHP PDO object has already been created. How do I do this?
// create PDO object and connect to MySQL
$dbh = new PDO( 'mysql:host=localhost;', 'name', 'pass' );
// create a database named 'database_name'
// select the database we just created ( this does not work )
$dbh->select_db( 'database_name' );
Is there a PDO equivalent to mysqli::select_db?
Perhaps I'm trying to use PDO improperly? Please help or explain.
EDIT
Should I not be using PDO to create new databases? I understand that the majority of benefits from using PDO are lost on a rarely used operation that does not insert data like CREATE DATABASE, but it seems strange to have to use a different connection to create the database, then create a PDO connection to make other calls.
Typically you would specify the database in the DSN when you connect. But if you're creating a new database, obviously you can't specify that database the DSN before you create it.
You can change your default database with the USE statement:
$dbh = new PDO("mysql:host=...;dbname=mysql", ...);
$dbh->query("create database newdatabase");
$dbh->query("use newdatabase");
Subsequent CREATE TABLE statements will be created in your newdatabase.
Re comment from #Mike:
When you switch databases like that it appears to force PDO to emulate prepared statements. Setting PDO::ATTR_EMULATE_PREPARES to false and then trying to use another database will fail.
I just did some tests and I don't see that happening. Changing the database only happens on the server, and it does not change anything about PDO's configuration in the client. Here's an example:
<?php
// connect to database
try {
$pdo = new PDO('mysql:host=huey;dbname=test', 'root', 'root');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
} catch(PDOException $err) {
die($err->getMessage());
}
$stmt = $pdo->prepare("select * from foo WHERE i = :i");
$result = $stmt->execute(array("i"=>123));
print_r($stmt->fetchAll(PDO::FETCH_ASSOC));
$pdo->exec("use test2");
$stmt = $pdo->prepare("select * from foo2 WHERE i = :i AND i = :i");
$result = $stmt->execute(array("i"=>456));
print_r($stmt->fetchAll(PDO::FETCH_ASSOC));
If what you're saying is true, then this should work without error. PDO can use a given named parameter more than once only if PDO::ATTR_EMULATE_PREPARES is true. So if you're saying that this attribute is set to true as a side effect of changing databases, then it should work.
But it doesn't work -- it gets an error "Invalid parameter number" which indicates that non-emulated prepared statements remains in effect.
You should be setting the database when you create the PDO object. An example (from here)
<?php
$hostname = "localhost";
$username = "your_username";
$password = "your_password";
try {
$dbh = new PDO("mysql:host=$hostname;dbname=mysql", $username, $password);
echo "Connected to database"; // check for connection
}
catch(PDOException $e)
{
echo $e->getMessage();
}
?>
Alternatively, you can select a MySQL database to use after a PHP PDO object has already been created as below:
With USE STATEMENT. But remember here USE STATEMENT is mysql command
try
{
$conn = new PDO("mysql:host=$servername;", $username, $password);
// set the PDO error mode to exception
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$conn->exec("use databasename");
//application logic
}
catch(PDOException $e)
{
echo $sql . "<br>" . $e->getMessage();
}
$conn = null;
I hope my code is helpful for requested
As far as I know, you have to create a new object for each connection. You can always extend the PDO class with a method which connects to multiple databases. And then use it as you like:
public function pickDatabase($db) {
if($db == 'main') {
return $this->db['main']; //instance of PDO object
else
return $this->db['secondary']; //another instance of PDO object
}
and use it like $yourclass->pickDatabase('main')->fetchAll('your stuff');

PHP PDO - can connect but query not working

I want to wean myself from the teat of the old mysql extension and am just doing a test PDO connection and simple query on a table in a database. I seem to be able to connect, ('connection successful' echoes out) but that's where the good times end. I have spent way too much time now just trying to get started with PDO.
<?php
$host = 'localhost';
$port = '3306';
$username = 'user';
$password = 'blabla';
$database = 'workslist';
try {
$db = new PDO("mysql:host=$host; port = $port; dbname = $database", $username, $password);
echo 'connection successful<br />';
$query = 'SELECT * FROM main';
$statement = $db->prepare($query);
$statement->execute();
$results = $statement->fetchAll();
$statement->closeCursor();
foreach($results as $r){
echo $r['work'] . '<br />';
}
} catch (PDOException $e) {
echo 'Error!: ' . $e->getMessage() . '<br />';
die();
}
?>
Is there anything wrong with the above?
The database name is 'workslist', the table name is 'main', and 'work' is one of the columns in that table. The PHP version I'm using is 5.3.4, and am using wamp on win7. I ran phpinfo() and under the PDO heading, the PDO drivers mysql, sqlite are enabled. To be sure the database and table actually exist I've tried it with MySQL and can return rows with the old mysql_fetch_array() method. I've checked the php.ini file to make sure the "extension=php_pdo..." lines are all uncommented.
cheers
This should work.
Please double-check that you actually have a table named "main" in that database.
Note that this error will not be discovered by PDO until you execute() the query, and if there is a problem with your query the default behavior is to return an empty result, not throw an exception.
To make PDO noisier, add the PDO::ERRMODE_EXCEPTION option when constructing PDO:
$db = new PDO("mysql:host=$host;port=$port;dbname=$database", $username, $password,
array(PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION)
);
Now check if you see the following:
Error!: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'workslist.main' doesn't exist
The particular problem is that spaces aren't allowed in the DSN string. With the spaces, the "dbname" directive isn't processed, so there's no default database. Besides removing the spaces, explicitly specifying the database in the statement can help prevent this sort of problem:
SELECT `work` FROM `workslist`.`main`
That way, should there not be a default database for some reason, the query will still succeed.
PDO won't throw an error unless you configure it to:
$db->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING );

Categories