I'm trying to use Google Cloud SQL over SSL from GCE(Google Compute Engine) instance. My problem is that I cannot connect to Cloud SQL instance over SSL.
mysql command works normally. I can connect to Cloud SQL instance with certification files.
mysql -uroot -p -h [IP Address] --ssl-ca=/home/user/.cert/server-ca.pem --ssl-cert=/home/user/.cert/client-cert.pem --ssl-key=/home/user/.cert/client-key.pem
However, I got warning and fatal error as followings when I access from PHP program.
<?php
$pdo = new PDO('mysql:host=[IP Address];dbname=testdb', 'root', 'test', array(
PDO::MYSQL_ATTR_SSL_KEY =>'/home/user/.cert/client-key.pem',
PDO::MYSQL_ATTR_SSL_CERT=>'/home/user/.cert/client-cert.pem',
PDO::MYSQL_ATTR_SSL_CA =>'/home/user/.cert/server-ca.pem'
)
);
$stmt = $pdo->query("SHOW TABLES;");
$row = $stmt->fetch(PDO::FETCH_ASSOC);
print_r($row);
?>
PHP Warning: PDO::__construct(): Peer certificate CN=`[GCP project name]:[Cloud SQL instance name]' did not match expected CN=`[IP Address]' in /tmp/mysql.php on line 7
Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[HY000] [2002] ' in /tmp/mysql.php on line 7
I got same error when I used mysqli.
$mysqli = mysqli_init();
mysqli_options($mysqli, MYSQLI_OPT_SSL_VERIFY_SERVER_CERT, true);
$mysqli->ssl_set('/home/user/.cert/client-key.pem',
'/home/user/.cert/client-cert.pem',
'/home/user/.cert/server-ca.pem',
NULL,NULL);
$mysqli->real_connect('[IP Address]', 'root', 'test', 'testdb', 3306, NULL, MYSQLI_CLIENT_SSL);
PHP Warning: mysqli::real_connect(): Peer certificate CN=`[GCP project name]:[Cloud SQL instance name]' did not match expected CN=`[IP Address]' in /tmp/mysql3.php on line 30
Warning: mysqli::real_connect(): (HY000/2002): in /tmp/mysql3.php on line 30
This question looks be relevant to my case but there is no answer yet. SSL self-signed certifications to connect with Mysql with PHP
Does anyone know about solutions?
Update 1
The bug is reported. https://bugs.php.net/bug.php?id=71003
Very similar question here. Google Cloud SQL SSL fails peer certificate validation
My PHP version is 5.6.14. I will update to 5.6.16 to use MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT.
Update 2
Fixed it when I use mysqli
What I did are as followings:
1 I updated my PHP to 5.6.20
sudo apt-get install php5
2 I put the MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT option like this.
$mysqli->real_connect('[IP Address]', 'root', 'test', 'testdb', 3306, NULL, MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT);
My application uses both mysqli and PDO for some reasons. I'm now looking for PDO's solution.
Update 3
This bug report shows about PDO's case. Sounds not fixed yet.
https://bugs.php.net/bug.php?id=71845
This is also related. https://groups.google.com/forum/?utm_medium=email&utm_source=footer#!msg/google-cloud-sql-discuss/4HNvmq7MpU4/kuSjhkS2AwAJ
As far as I understand, there is no way to resolve for PDO.
Update 4
Some people blame google's design of CN names (I agree with them actually..)
What's worst is you guys use impossible CN names (:) . If the CN was without colon maybe I can map the ip and the CN in my hosts file so that when peer validation is done it can pass. With the colon, php thinks is host and is port
and Google's staff? understand the problem.
I understand the current situation when connecting by IP is not ideal.
But it seems they provide a solution called 'proxy'.
https://groups.google.com/forum/#!topic/google-cloud-sql-discuss/gAzsuCzPlaU
I'm using Cloud SQL second generation and my applications are hosted GCE. So I think I can use the proxy way. I will try it now.
Update 5
Setup the proxy access. Solved both PDO and mysqli access.
Install the proxy on Ubuntu
$ wget https://dl.google.com/cloudsql/cloud_sql_proxy.linux.amd64
$ mv cloud_sql_proxy.linux.amd64 cloud_sql_proxy
$ chmod +x cloud_sql_proxy
$ sudo mkdir /cloudsql; sudo chmod 777 /cloudsql
$ ./cloud_sql_proxy -dir=/cloudsql -instances=<project name>:us-central1:mydb
PDO
<?php
$pdo = new pdo('mysql:unix_socket=/cloudsql/<project name>:us-central1:mydb;dbname=testdb','root','test');
$stmt = $pdo->query("SHOW TABLES;");
$row = $stmt->fetch(PDO::FETCH_ASSOC);
print_r($row);
?>
mysqli
$mysqli = mysqli_connect('localhost', 'root', 'test', 'testdb', 3306, '/cloudsql/<project name>:us-central1');
$sql = "SELECT id FROM users";
if ($result = $mysqli->query($sql)) {
while ($row = $result->fetch_assoc()) {
echo $row["id"] . "\n";
}
$result->close();
}
$mysqli->close();
refs (Japanese)
http://blog.hrendoh.com/connecting-to-google-cloud-sql-using-mysql-client/
http://blog.hrendoh.com/google-appengine-php-using-cloud-sql/
For PDO connections that don't use Google cloud or cannot benefit from the proxy solution, they have fixed the bug and it is merged now.
There is now a constant for this (starting April 2017):
PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => false,
http://git.php.net/?p=php-src.git;a=commit;h=247ce052cd0fc7d0d8ea1a0e7ea2075e9601766a
In short, use Cloud SQL Proxy if you need to access from both PDO and mysqli. You have no choice.
https://cloud.google.com/sql/docs/sql-proxy
For mysqli, adding:
MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT
to real_connect() solved my instance of this issue.
Example (replace host, user, password and database as needed):
$db_connection->real_connect('ip address or host', 'user', 'password', 'database', 3306, NULL, MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT);
Full php mysqli SSL connection script:
// check if openssl is enabled on server
if(!extension_loaded('openssl')) {
throw new Exception('This app needs the Open SSL PHP extension and it is missing.');
}
// start connection
$db_connection = mysqli_init();
// set ssl config (update with your certs location)
$db_connection->ssl_set('/etc/my.cnf.d/certs/client-key.pem','/etc/my.cnf.d/certs/client-cert.pem', '/etc/my.cnf.d/certs/ca-cert.pem', NULL, NULL);
// connect (update with your host, db and credentials)
$db_connection->real_connect('ip address or host', 'user', 'password', 'database', 3306, NULL, MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT);
Example in CakePHP 3.5.x + PHP 7.1.x + SQL Google Cloud + SSL
Change file in: config/app.php
...
...
/**
* The test connection is used during the test suite.
*/
'default' => [
'className' => 'Cake\Database\Connection',
'driver' => 'Cake\Database\Driver\Mysql',
'persistent' => false,
'host' => 'xx.xxx.xxx.xxx',
//'port' => 'non_standard_port_number',
'username' => 'user_name_x',
'password' => 'pass_x',
'database' => 'bd_name_x',
'encoding' => 'utf8',
'timezone' => 'UTC',
'cacheMetadata' => true,
'quoteIdentifiers' => false,
'log' => false,
'flags' => [
PDO::MYSQL_ATTR_SSL_KEY => CONFIG.'client-key.pem',
PDO::MYSQL_ATTR_SSL_CERT => CONFIG.'client-cert.pem',
PDO::MYSQL_ATTR_SSL_CA => CONFIG.'server-ca.pem',
PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => false
],
//'ssl_key' => CONFIG.'client-key.pem',
//'ssl_cert' => CONFIG.'client-cert.pem',
//'ssl_ca' => CONFIG.'server-ca.pem',
//'init' => ['SET GLOBAL innodb_stats_on_metadata = 0'],
],
],
...
...
Example PHP Pure + PDO + SSL:
$ssl_key = CONFIG.'client-key.pem';
$ssl_cert = CONFIG.'client-cert.pem';
$ssl_ca = CONFIG.'server-ca.pem';
$pdo = new PDO('mysql:host=xxx.xxx.xxx.xxx;dbname=db_name_x', 'user_name_x', 'pass_x', array(
PDO::MYSQL_ATTR_SSL_KEY => '/path/full/client-key.pem',
PDO::MYSQL_ATTR_SSL_CERT => '/path/full/client-cert.pem',
PDO::MYSQL_ATTR_SSL_CA => '/path/full/server-ca.pem',
PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => false
)
);
$statement = $pdo->query("SHOW TABLES;");
var_dump($statement);
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo json_encode($row);
exit();
I had the same problem with a MySQL database hosted at compose cluster.
After searching and testing for hours, I found out that the best solution is to disable testing the certificate provided by the server by using the MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT flag.
I haven't tested it with PDO but with the mysqli interface it is working for me.
In general this problem would appear with a database hosted at a cluster server.
Related
I use MySQL 5.7.17 on AWS RDS.
I encountered a strange behavior and I am looking for an explanation.
In short: I try to connect over SSL, with settings that I think should cause the connection to FAIL, but it succeeds!
The following PHP code succeeds to connect to the RDS instance over SSL:
<?
$HOST = "something.amazonaws.com";
$USER = "myuser";
$PASS = "mypass";
$connectionString = "mysql:host={$HOST};charset=utf8";
$options = [ ];
$options[PDO::MYSQL_ATTR_SSL_CA] = "LITERALLY THIS TEXT. DEFINITELY NOT A CERTIFICATE!";
$options[PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = false;
$conn = new \PDO($connectionString, $USER, $PASS, $options);
$sql = "SHOW STATUS LIKE 'Ssl_cipher'";
$stmt = $conn->prepare($sql);
$stmt->execute([ ]);
$stmt->setFetchMode(\PDO::FETCH_ASSOC);
$rows = $stmt->fetchAll();
print_r($rows);
The result I get:
Array
(
[0] => Array
(
[Variable_name] => Ssl_cipher
[Value] => AES256-SHA
)
)
Also, I found three pem files in /etc/ca-certificates/rds-mysql. I thought that PHP might be going there for some reason, so I deleted them, but the SSL connection still succeeds.
Note: if I delete the line that says $options[PDO::MYSQL_ATTR_SSL_CA] = "LITERALLY THIS TEXT. DEFINITELY NOT A CERTIFICATE!"; - it does NOT connect over SSL. So it appears that this option does have some impact.
My question is: how come it succeeds?
I've installed Moodle with Postgres. The db configuration looks like (yeah, I did it in a bit hackish way):
$CFG->dbtype = 'pgsql'; // 'pgsql', 'mariadb', 'mysqli', 'mssql', 'sqlsrv' or 'oci'
$CFG->dblibrary = 'native'; // 'native' only at the moment
$CFG->dbhost = "my-moodle-db.net' connect_timeout=10 sslmode=verify-full sslrootcert='/path/to/cas/allCAs.pem"; // eg 'localhost' or 'db.isp.com' or IP
$CFG->dbname = $pwd_name; // database name, eg moodle
$CFG->dbuser = 'moodle'; // your database username
$CFG->dbpass = $pwd_pwd; // your database password
$CFG->prefix = 'mdl_'; // prefix to use for all table names
$CFG->dboptions = array(
'dbpersist' => true, // should persistent database connections be
...
My installation works almost fine but once in roughly 10 requests I'm getting the following error:
Error: Database connection failed
And the page is rendered immediately though I set connection timeout to 10 above.
Is there any other place to fix connection timeouts in PHP?
Can I make moodle somehow retry the connection before returning the error to me?
I'm using Apache server on Windows 8, XAMPP 1.8.1, PHP 5.4.7 and MySQL.
I've decided to convert my code to PDO.
Checking my phpinfo() it appears that the PDO driver for MySQL is enabled, but I still keep on getting the "could not find driver" error.
Here's the code:
<?php
//connect to database
$config['db'] = array(
'host' => 'localhost',
'username' => 'root',
'password' => '',
'dbname' => 'x'
);
$db = new PDO("
pdo_mysql:host= " .$config['db']['host']. ";
dbname= " .$config['db']['dbname']. ";
username= " .$config['db']['username'].";
password= " .$config['db']['password']."
");
?>
And the error:
Fatal error: Uncaught exception 'PDOException' with message 'could not find driver'
Any suggestions?
Let me suggest you refer to the manual page and get the proper DSN string example from there
What happens if you change the DSN prefix from pdo_mysql to just mysql?
As manual says link
You should format your dsn in this way:
DRIVER:host=YOURHOST;dbname=YOURDB
Also to create the instance you should act like this: $db = new PDO($dsn, $username, $password)
Also I forgot to say (as other users have pointed out) your DRIVER is "mysql" and not pdo_mysql
In the end there were 2 problems with the code:
1. pdo_mysql -> mysql
2. username and password should be passed as variables and not as strings.
The correct code is:
$config['db'] = array(
'host' => 'localhost',
'username' => 'root',
'password' => '',
'dbname' => 'x'
);
$db = new PDO (
"mysql:host=".$config['db']['host'].";dbname=".$config['db']['dbname']."",
$config['db']['username'],
$config['db']['password']
);
I've been trying to connect to my MYSQL database on my newly acquired website through a PDO connection which is quoted below, and it doesn't seem to be working properly, as it fails as soon as I try using a query or to add an entry. All the information seems to be right, but whenever I try using any command, as selecting or adding entries, it gives me this error:
Array ( [0] => 3D000 [1] => 1046 [2] => No database selected ) 1
Here are the lines of my connection:
try {
$db = new PDO('mysql:localhost;dbname=username_dbName', 'username_dbUser', 'password');
}
catch (Exception $e) {
die('Erreur : ' . $e->getMessage());
print 'Unable to Connect. Please contact the website administrator.';
}
And here is the code I used to test if queries worked.
$req = $db->prepare('INSERT INTO testTable(number)
VALUES(:number)');
$req->execute(array('number' => 13)) or die(print_r($req->errorInfo()));
Obviously I use the actual login values for the connection, but it's not working and I can't figure why.
My website is hosted by HostGator, if that can help.
Thanks in advance for your answers!
Try this
try {
$db = new PDO('mysql:dbname=username_dbName;host=localhost', 'username_dbUser', 'password');
}
I think a problem is with localhost you indicate. Some hosting services require you to use something other than localhost. You might perhaps try 127.0.0.1 instead of it.
If it does not help and you are sure your username, password, and database parameters are all the way correct, I believe you will need to ask your hosting provider for a correct mysql server address.
in your real code is username_dbName a variable, like $username_dbName ? In that case you should use double quotes instead of single quotes.
"mysql:localhost;dbname=$username_dbName"
Try
$host = 'localhost';
$dbname = 'username_dbName';
$username = 'username_dbUser';
$pw = 'password';
$db = new PDO("mysql:host=$host;dbname=$dbname", $username, $pw);
EDIT: corrected typo
try this:
'driver' => 'mysql',
'host' => '(use the server IP address)',
'database' => '(database Name)',
'username' => '(database Username)',
'password' => '(the password you entered for that database user)',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => ''
I am attempting to set up a db connection for a mysqli_connect statement $dbc. I had it working in my script with the following:
DEFINE ('DB_USER','myName';
DEFINE ('DB_PASSWORD','somePass123';
DEFINE ('DB_HOST','localhost';
DEFINE ('DB_NAME','sitename';
// make the db connection
$dbc = #mysqli_connect(DB_HOST,DB_USER,DB_PASSWORD,DB_NAME)
OR die ('Could not connect to mysql: ' . mysqli_connect_error());
I then posted a question on SO about security and best practice and was advised that if the connection variables (password, host, dbname, user) exist elsewhere in a separate database configuration file, that I should call the variables for the connection from there.
Here is the relevant snippet from the file in config/database/php
$config['default'] = array(
'benchmark' => TRUE,
'persistent' => FALSE,
'connection' => array(
'type' => 'mysqli',
'user' => 'myName',
'pass' => 'somepass123',
'host' => 'localhost',
'port' => FALSE,
'socket' => FALSE,
'database' => 'sitename',
),
'character_set' => 'utf8',
'table_prefix' => '',
'object' => TRUE,
'cache' => FALSE,
'escape' => TRUE
);
So I then tried this:
DEFINE ('DB_USER','$config['default']['connection']['user'])';
DEFINE ('DB_PASSWORD',$config['default']['connection']['pass']);
DEFINE ('DB_HOST',$config['default']['connection']['host']);
DEFINE ('DB_NAME',$config['default']['connection']['database']);
// make the db connection
$dbc = #mysqli_connect(DB_HOST,DB_USER,DB_PASSWORD,DB_NAME)
OR die ('Could not connect to mysql: ' . mysqli_connect_error());
Which produced the following error when I tried to load the page:
"Undefined variable: config"
I then tried this:
$dbc = #mysqli_connect(
$config['default']['connection']['host'],
$config['default']['connection']['user'],
$config['default']['connection']['pass'],
$config['default']['connection']['database'])
OR die ('Could not connect to mysql: ' . mysqli_connect_error());
// Set the encoding
mysqli_set_charset($dbc, 'utf8');
// set the query variable
$query = "SELECT MAX(rating_date)
AS last_date
FROM rating
WHERE incident_id = $incident_id;";
//connect and run the query
$result = mysqli_query($dbc, $query);
echo $result->fetch_object()->last_date;
?>
Which then produced the following error:
"Fatal error: Call to a member function fetch_object() on a non-object in..."
I'm not 100% sure what this is telling me. Yesterday I learned that one cannot echo a SQL query in php directly because it's an object so I cut n pasted the part "echo $result->fetch_object()->last_date;" which worked.
It seems that now that I am trying to draw upon the variables from config, rather than just define them in the function, I am unable to connect perhaps due to a scope issue?
The file with the $dbc connection is in a folder themes/myname/views/reports/detail.php
The file with the database configuration details array is in application/config/database.php
It looks like an issue of variable scope?
What would be the best practice here in making my $dbc variable? How do I call the variables from database.php when it exists in a different directory than the file where I'm calling it? Must I include() the whole file?
How about something sane like:
$dbc = #mysqli_connect(
$config['default']['connection']['host'],
$config['default']['connection']['user'],
$config['default']['connection']['pass'],
$config['default']['connection']['database'])
OR die ('Could not connect to mysql: ' . mysqli_connect_error());
You don't gain anything by using define(), you're only trying to avoid putting the raw strings with your username and password into the mysqli_connect() call in case an error occurs and that line gets sent to the client in an error message/stack trace.
Constants are global and you don't need to set them as global to retrieve them from the memory but variables are not, if you are calling the variable $config from inside a function you have two ways to call it:
Set the variable to be global at the first beginning of your function that you are calling this variable from global $config;
OR
Call the variable using the $GLOBALS variable $config = $GLOBALS['config'];