$db_connection = $_SERVER['DOCUMENT_ROOT'] . '/includes/install/database_connection.php';
if (!file_exists($db_connection)) {
require("install/xmlapi.php");
if (isset($_POST['cpname'])) {
$opts['user'] = $_POST['cpname'];
$opts['pass'] = $_POST['cppass'];
$opts['temp'] = substr(str_shuffle(md5(time())),0,'12');
$xmlapi = new xmlapi($_SERVER['HTTP_HOST']);
$xmlapi->set_port( 2083 );
$xmlapi->password_auth($opts['user'],$opts['pass']);
$xmlapi->set_debug(0);
$cpaneluser=$opts['user'];
$databasename="OSMP_DAT";
$databaseuser="OSMP_admin";
$databasepass=$opts['temp'];
$db = $databasename;
$user = $databaseuser;
$pass = $databasepass;
$loc = 'localhost';
$createdb = $xmlapi->api1_query($cpaneluser, "Mysql", "adddb", array($databasename));
$usr = $xmlapi->api1_query($cpaneluser, "Mysql", "adduser", array($databaseuser, $databasepass));
$addusr = $xmlapi->api1_query($cpaneluser, "Mysql", "adduserdb", array("".$cpaneluser."_".$databasename."", "".$cpaneluser."_".$databaseuser."", 'all'));
include ('install/installer.php');
exit;
}
if (!isset($_POST['dbhost'])) { include ('install/db_installer.php'); }
if (isset($_POST['dbhost'])) {
// save connection details to $db_connection
}
}
The above code works flawlessly as one would expect.
First it checks for the existence of database_connection.php. If it exists, it includes the file which contains database details.
If not - we are assuming its a first time install. So we are asking a user for cpanel login details, and our script creates the database and saves details to database_connection.php.
The only problem ... is database prefixes. When the database is created, if the WHM has database prefixes set for the user account, then a database prefix is prefixed to the database name.
I want to know how to determine if there is a prefix, and if so how to find out what it is so the script can prefix it on the database name as well.
Note I am not seeking a table prefix, but rather the database prefix as added by cpanel/whm
So apparently cpanel by default if prefixing is enabled used the first 8 characters of ones username followed by an underscore. This is used for both database and database names.
So I simply modified the above code as follows:
$db_connection = $_SERVER['DOCUMENT_ROOT'] . '/includes/install/database_connection.php';
if (!file_exists($db_connection)) {
require("install/xmlapi.php");
if (isset($_POST['cpname'])) {
$opts['user'] = $_POST['cpname'];
$prefix = substr($opts['user'],0,8).'_';
if ($prefix === FALSE) {$prefix = $opts['user'];}
$opts['pass'] = $_POST['cppass'];
$opts['temp'] = substr(str_shuffle(md5(time())),0,'12');
$xmlapi = new xmlapi(localhost);
$xmlapi->set_port( 2083 );
$xmlapi->password_auth($opts['user'],$opts['pass']);
$xmlapi->set_debug(1);
$cpaneluser=$opts['user'];
$databasename="OSMP_DAT";
$databaseuser="osmp";
$databasepass=$opts['temp'];
$pass = $databasepass;
$loc = 'localhost';
$createdb = $xmlapi->api1_query($cpaneluser, "Mysql", "adddb", array($databasename));
$usr = $xmlapi->api1_query($cpaneluser, "Mysql", "adduser", array($databaseuser, $databasepass));
$addusr = $xmlapi->api1_query($cpaneluser, "Mysql", "adduserdb", array($databasename, $databaseuser, 'all'));
$db = $prefix.$databasename;
$user = $prefix.$databaseuser;
include ('install/installer.php');
exit;
}
if (!isset($_POST['dbhost'])) { include ('install/db_installer.php'); }
if (isset($_POST['dbhost'])) {
// save connection details to $db_connection
}
}
So now a check is done to determine the length of the username and if longer than 8 characters, its truncated to 8. Then the understore is added and output as variables to pass along to the next part of the script.
The only flaw left as I can see is if the host has disabled the prefixing in whm, so I am well on my way.
For anyone attempting to use this code in the future - make note you
need to secure the included files or you are going to have whopping
security problems. As this code stands someone could manually call
install/db_installer.php or install/installer.php and bypass the
(!file_exists($db_connection)) check and the if (isset($_POST)) and
the (!isset($_POST['dbhost'])).
DO NOT USE THIS CODE IF YOU DON'T KNOW HOW TO SECURE IT!
Related
I'm using a PHP file stored on my host to connect to a database stored on the same host, this is working fine.
I am using the below to connect to the database (example connection details)
<?php
$db = new PDO('mysql:host=localhost;dbname=myDB', 'myusername', 'mypassword');
My question is; seeing as I have specified the password (and other details) to connect to my server in my PHP file, can't someone with the direct link to my PHP file just download it and open it in a text editor to see those details?
If so, should I be passing the connection details to the php file like this:
<?php
$server = $_POST['server'];
$database = $_POST['database'];
$username = $_POST['username'];
$password = $_POST['password'];
$db = new PDO('mysql:host=$server;dbname=$database', $username, $password);
Expanding a bit on my comment, ideally you want to have this in separate files, one used for global configuration you can then import to your other modules like the example below.
Config.php file:
<?php
$HOST = 'hostname';
$DB = 'dbname';
$USER = 'username';
$PWD = 'password';
... other variables and global config ...
?>
DB Connection File:
<?php
include 'config.php';
$db = new PDO("mysql:host=$HOST;dbname=$DB", $USER, $PWD);
?>
Notice how the string inside the PDO connection is double quoted, because if single quoted, string interpolation won't work.
Your variable $server and $database are not interpreted correctly as you are using single quote '. You need to use double quote " to correctly pass variable values. (Refer for more details What is the difference between single-quoted and double-quoted strings in PHP?) Change your code as below.
<?php
$server = $_POST['server'];
$database = $_POST['database'];
$username = $_POST['username'];
$password = $_POST['password'];
// Replaced ' with "
$db = new PDO("mysql:host=$server;dbname=$database", $username, $password);
I want to create a DB for each user who wants to register to my Web-app. When i try this local everything perfectly works. A User can register with his email and pw. A DB is created and a import.sql file is imported so that the DB created for the User is empty on data but the tables and realtioships are given.
My Host uses cPanel and phpMyAdmin to create DB and db-user. I want to do this with php like i do it local. Does anyone have an idea how i get this done?
I've already searched and tryed stuff out but nothing works for me.
If possible some explanations on cPanel maybe would be enough.
<?php
require("xmlapi.php"); // this can be downlaoded from https://github.com/CpanelInc/xmlapi-php/blob/master/xmlapi.php
$xmlapi = new xmlapi("cpanlel host name");
$xmlapi->set_port( 2083 );
$xmlapi->password_auth('cpanel username','cpanel passsword');
$xmlapi->set_debug(0);//output actions in the error log 1 for true and 0 false
$cpaneluser='cpanel username';
$databasename="something";
$databaseuser="database username";
$databasepass= 'database password';
//create database
$createdb = $xmlapi->api1_query($cpaneluser, "Mysql", "adddb", array($databasename));
//create user
$usr = $xmlapi->api1_query($cpaneluser, "Mysql", "adduser", array($databaseuser, $databasepass));
//add user
$addusr = $xmlapi->api1_query($cpaneluser, 'Mysql', 'adduserdb', array('' . $databasename . '', '' . $databaseuser . '', 'all'));
?>
Using the above code you will be able to create new database, add new user to database and give all access to user on database.
The database test_new_1 is able to create for the user testcom directly from the cpanel, But not able to create through php. Another server it is working properly, the only difference username and database prefix is same in that server.
Error Shows:
Error creating database: Access denied for user 'testcom'#'localhost' to database 'test_new_1'
PHP
// Create connection
$conn = mysqli_connect('localhost', 'testcom', '123456');
// Check connection
if (!$conn)
{
die("Connection failed: " . mysqli_connect_error());
}
// Create database
$sql = "CREATE DATABASE IF NOT EXISTS test_new_1";
if (mysqli_query($conn, $sql))
{
echo "Database created successfully";
}
else
{
echo "Error creating database: " . mysqli_error($conn);
}
cPanel does not allow you to create databases directly from with MySQL function. You need to use the API provided to you by cPanel:
Download xmlapi.php from https://github.com/CpanelInc/xmlapi-php/blob/master/xmlapi.php then use it:
<?php
include("xmlapi.php");
$db_host = 'yourdomain.com';
$cpaneluser = 'your cpanel username';
$cpanelpass = 'your cpanel password';
$databasename = 'testdb';
$databaseuser = 'test'; // Warning: in most of cases this can't be longer than 8 characters
$databasepass = 'dbpass'; // Warning: be sure the password is strong enough, else the CPanel will reject it
$xmlapi = new xmlapi($db_host);
$xmlapi->password_auth("".$cpaneluser."","".$cpanelpass."");
$xmlapi->set_port(2082);
$xmlapi->set_debug(1);//output actions in the error log 1 for true and 0 false
$xmlapi->set_output('array');//set this for browser output
//create database
$createdb = $xmlapi->api1_query($cpaneluser, "Mysql", "adddb", array($databasename));
//create user
$usr = $xmlapi->api1_query($cpaneluser, "Mysql", "adduser", array($databaseuser, $databasepass));
//add user
$addusr = $xmlapi->api1_query($cpaneluser, "Mysql", "adduserdb", array("".$cpaneluser."_".$databasename."", "".$cpaneluser."_".$databaseuser."", 'all'));
?>
Found lots of similar problems on this site, but the solutions for those issues don't seem to reply. The user in question has full access to the database, and from what I can tell I'm not missing any commas etc. A second set of eyes would be great.
Submitted signature is in an acceptable formatTrying to open a connectionError!: SQLSTATE[42000] [1044] Access denied for user 'emkinsti_user1'#'localhost' to database 'signatures'
<?php
// Tracks what fields have validation errors
$errors = array();
// Default to showing the form
$show_form = true;
// 1. Get the input from the form
// Using the PHP filters are the most secure way of doing it
$name = filter_input(INPUT_POST, 'name', FILTER_SANITIZE_STRING);
$output = filter_input(INPUT_POST, 'output', FILTER_UNSAFE_RAW);
// 2. Confirm the form was submitted before doing anything else
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// 3. Validate that a name was typed in
if (empty($name)) {
$errors['name'] = true;
}
// 3. Validate that the submitted signature is in an acceptable format
if (!json_decode($output)) {
$errors['output'] = true;
}
}
// No validation errors exist, so we can start the database stuff
if (empty($errors)) {
echo "Submitted signature is in an acceptable format";"<br/>";
$dsn = 'mysql:host=localhost;dbname=signatures';
$user = 'emkinsti_user1';
$pass = '6nqq103t26';
}
// 4. Open a connection to the database using PDO
try {
echo "Trying to open a connection";
$db = new PDO($dsn, $user, $pass);
}
catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "<br/>";
die();
}
// Make sure we are talking to the database in UTF-8
$db->exec('SET NAMES utf8');
// Create some other pieces of information about the user
// to confirm the legitimacy of their signature
$sig_hash = sha1($output);
$created = time();
$ip = $_SERVER['REMOTE_ADDR'];
// 5. Use PDO prepare to insert all the information into the database
$sql = $db->prepare('INSERT INTO signatures (signator, signature, sig_hash, ip, created)
VALUES (:signator, :signature, :sig_hash, :ip, :created)');
$sql->bindValue(':signator', $name, PDO::PARAM_STR);
$sql->bindValue(':signature', $output, PDO::PARAM_STR);
$sql->bindValue(':sig_hash', $sig_hash, PDO::PARAM_STR);
$sql->bindValue(':ip', $ip, PDO::PARAM_STR);
$sql->bindValue(':created', $created, PDO::PARAM_INT);
$sql->execute();
// 6. Trigger the display of the signature regeneration
$show_form = false;
// mysql_close($db);
$db = null;
?>
emkinsti_user1'#'localhost' to database 'signatures'
if you are using CPanel, CPanel uses prefixes also to the database name:
You used: emkinsti_user1 as users.
You should use: emkinsti_signatures as database name.
Log in into your CPanel and there you will find the database name with prefix
Try http://php.net/manual/en/pdo.getavailabledrivers.php to see if the database is supported by PDO.
<?php
print_r(PDO::getAvailableDrivers());
?>
Just an idea. I would expect another error message when it isn't. So, as far as I can tell, the user has no access when accessing the database from the local host.
I'm in the process of adding password hashing and SQL injection defenses into my Login system. Currently, I've ran into an error.
<?php
session_start(); //start the session for user profile page
define('DB_HOST','localhost');
define('DB_NAME','test'); //name of database
define('DB_USER','root'); //mysql user
define('DB_PASSWORD',''); //mysql password
$con = new PDO('mysql:host=localhost;dbname=test','root','');
function SignIn($con){
$user = $_POST['user']; //user input field from html
$pass = $_POST['pass']; //pass input field from html
if(isset($_POST['user'])){ //checking the 'user' name which is from Sign-in.html, is it empty or have some text
$query = $con->prepare("SELECT * FROM UserName where userName = :user") or die(mysqli_connect_error());
$query->bindParam(':user',$user);
$query->execute();
$username = $query->fetchColumn(1);
$pw = $query->fetchColumn(2);//hashed password in database
//check username and password
if($user==$username && password_verify($pass, $pw)) {
// $user and $pass are from POST
// $username and $pw are from the rows
//$_SESSION['userName'] = $row['pass'];
echo "Successfully logged in.";
}
else {
echo "Invalid.";
}
}
else{
echo "INVALID LOGIN";
}
}
if(isset($_POST['submit'])){
SignIn($con);
}
?>
In the above code, when I enter a valid username and password, the system prints out "Invalid". It could be a error in the password_verify() in the if statement(because if I remove it, I login successfully). I'm pretty sure I've done the preparing, binding and execution of the query properly? Does anyone know why it is doing this?
Thanks!
You're doing a SELECT *, and using fetchColumn, so the results are dependent of the returned columns order. You should either select the specific columns you need, or fetch the whole row as an associative array , and access it by column name.
There are other two issues that you should fix:
You shouldn't be using mysqli_connect_error() as you're using PDO. The right function would be $con->errorInfo().
You're defining some constants with the connection settings, yet you don't use them on the PDO() call, repeating the values instead.
Use
// it will be an array('name' => 'John', 'password_hash' => 'abcd')
// or FALSE if user not found
$storedUser = $query->fetch(PDO::FETCH_ASSOC);
instead of
$username = $query->fetchColumn(1);
$pw = $query->fetchColumn(2);
Because fetchColumn moves cursor of result. So first call extracts 1 column of first row, and second call will extract data from SECOND row!