My question is, how efficient are PHP Mysqli prepared statements? From what I have understand from basic reading, prepared statements 1) help in security using bound inputs 2) speed up and 'reduce' data sent to the server by somewhat 'pre-packaging' or 'preparing' the sql query to an extent, and once data is available, it just attaches the data to the prepared statement and executes it. This also helps on 'repeated' use of the same statement when inserting the same data (different values) repeatedly, because the statement is prepared only once.
Now, I am building a website with several functionalities, and all (or most) of them use JQuery and AJAX to get obtain user input, do some checks (either in the JS/JQ or in PHP), Send the data to a PHP file PHP_AJAX_Handler.php specified in the AJAX URL. The PHP file prepares the SQL statemtns to insert data into database, then return JSON success/failure messages. For example, most of my features/functionality are programmed as follows; below is one file which I am using to 1) check for existing continent-country pair, and 2) insert the new continent-country pair.
HTML:
<input type='text' id='continent'>
<input type='text' id='country'>
<button id='btn1'></button>
<p id='p1'></p>
<p id='p2'></p>
<p id='p3'></p>
JQuery:
$("#btn1")click(function(){
var Cntt = $("#continent").val();
var Ctry = $("#country").val();
$.post("PHP_AJAX_Handler.php",{CN:cntt,CT:ctry},function(DAT)
{ var RET_j = json.PARSE(dat);
if(RET_j.PASS=='FAIL')
{ $('#p1').html(RET_j.PASS);
$('#p2').html(RET_j.MSG1);
}
if(RET_j.PASS=='OKAY')
{ $('#p1').html(RET_j.PASS);
$('#p3').html(RET_j.MSG2);
} }
);
});
PHP_AJAX_Handler.php
<?PHP
session_start();
if( (isset($_POST['CT'])) && (isset($_POST['CN'])))
{ require_once ("golin_2.php");
$CN = $_POST['CN'];
$CT = $_POST['CT'];
$ER = "";
$CONN = mysqli_connect($SERVER, $USER, $PASS, $DBNAME);
If($CONN == FALSE)
{ $ER = $ER . "Err: Conn Could not connect to Databse ".mysqli_connect_errno().' '.mysqli_connect_error();
}
else
{ $SQL_1 = "SELECT * FROM sailors.continental_regions WHERE CONTINENT = ? AND COUNTRY = ?";
if(!($STMT_1 = mysqli_stmt_init($CONN)))
{ $ER = $ER . "Err: Stmt Prepare Failed";
}
else
{ if(!mysqli_stmt_prepare($STMT_1, $SQL_1)) ///FIRST SET of prepared statement lines
{ $ER = $ER . "Err: Stmt Prepare Failed";
}
else
{ if(!mysqli_stmt_bind_param($STMT_1,"ss",$CN, $CT))
{ $ER = $ER . "Err: Stmt Prepare Failed";
}
else
{ if(!(mysqli_stmt_execute($STMT_1)))
{ $ER = $ER . "Err: Stmt_1 Execute Failed";
}
else
{ $RES_1 = mysqli_stmt_get_result($STMT_1);
$NUMROWS_1 = mysqli_num_rows($RES_1);
if($NUMROWS_1>0)
{ $ER = $ER . "Err: duplicate '$CN' '$CT' pair";
}
if($NUMROWS_1==0)
{ $SQL_2 = "INSERT INTO DB.continental_regions (CONTINENT,COUNTRY) values (?, ?)";
if(!($STMT_2=(mysqli_stmt_init($CONN))))
{ $ER = $ER . "Err: Init2 failed";
}
else
{ if(!mysqli_stmt_prepare($STMT_2, $SQL_2)) ///SECOND SET of prepared statement lines
{ $ER = $ER . "Err: Prep2 failed".mysqli_error($CONN);
}
else
{ if(!mysqli_stmt_bind_param($STMT_2,"ss",$CN, $CT))
{ $ER = $ER . "Err: Bind2 failed";
}
else
{
if(!(mysqli_stmt_execute($STMT_2)))
{ $ER = $ER . "Err: Exec failed";
}
else
{ $arr['PASS'] = 'OK';
}
}
}
}
}
}
}
}
}
mysqli_free_result($RES_1);
mysqli_stmt_close($STMT_1);
mysqli_stmt_close($STMT_2);
mysqli_close($CONN);
}
if($ER!=="")
{ $arr['MSG'] = $ER;
$arr['PASS'] = 'FAIL';
}
if($arr['PASS']=="OK")
{ $arr['MSG2'] = "Insert Success";
}
echo json_encode($arr);
}
else
{ header("location: ../Error_Fail.php");
}
?>
As you can see, the PHP file is turning out to be pretty long. There is one set of prepare statements to check if the CC pair exists already in table, then another to insert the CC pair.
From what I see, for each AJAX request to add a new pair of values, the mysqli statements are prepared over again. Then again for the next request, and so on. I imagine this is creating a lot of overhead and data to the server just to achieve Security. Is this true for other people developing web applications with AJAX-POST-PHP? to me it seems unavoidable that for each prepare, values can only be inserted one time? How to get around to preparing this statement once, and only doing repeat executes whence data is available? I can't seem to get my head around the 'efficiency' factor of prepared statements..
Thanks.. would appreciate some advise from some seasoned programmers out there..
You said:
As you can see, the PHP file is turning out to be pretty long.
That is true, but that is not the fault of prepared statements. You must have been learning PHP development from a poorly written tutorial. This code does not need to be so long. In fact, it can be severely shortened.
Just fixing your existing code made it much more readable. I used OOP-style mysqli and I removed all these if statements. You should enable error reporting instead.
<?php
session_start();
if (isset($_POST['CT'],$_POST['CN'])) {
require_once "golin_2.php";
$CN = $_POST['CN'];
$CT = $_POST['CT'];
$ER = "";
$arr = [
'PASS' => "OK",
'MSG2' => "Insert Success",
]; // successful state should be the default outcome
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$CONN = new mysqli($SERVER, $USER, $PASS, $DBNAME);
$CONN->set_charset('utf8mb4'); // always set the charset
// To check existance of data in database we use COUNT(*)
$stmt = $CONN->prepare("SELECT COUNT(*) FROM sailors.continental_regions WHERE CONTINENT = ? AND COUNTRY = ?");
$stmt->bind_param("ss", $CN, $CT);
$stmt->execute();
$NUMROWS = $stmt->get_result()->fetch_row()[0];
if ($NUMROWS) {
$ER .= "Err: duplicate '$CN' '$CT' pair";
} else {
$stmt = $CONN->prepare("INSERT INTO DB.continental_regions (CONTINENT,COUNTRY) values (?, ?)");
$stmt->bind_param("ss", $CN, $CT);
$stmt->execute();
}
if ($ER) {
$arr = [
'PASS' => "FAIL",
'MSG' => $ER,
];
}
echo json_encode($arr);
} else {
header("location: ../Error_Fail.php");
}
If you have a composite UNIQUE key on these two columns in your table then you can remove the select statement. Also, you should clean up your response preparation. The successful state should be the default and it should be replaced with the error message only if something went wrong.
In this example, I removed one SQL statement. The whole thing is now much simpler.
<?php
define('DUPLICATE_KEY', 1062);
session_start();
if (isset($_POST['CT'],$_POST['CN'])) {
require_once "golin_2.php";
$CN = $_POST['CN'];
$CT = $_POST['CT'];
$arr = [
'PASS' => "OK",
'MSG2' => "Insert Success",
]; // successful state should be the default outcome
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$CONN = new mysqli($SERVER, $USER, $PASS, $DBNAME);
$CONN->set_charset('utf8mb4'); // always set the charset
try {
$stmt = $CONN->prepare("INSERT INTO continental_regions (CONTINENT,COUNTRY) values (?, ?)");
$stmt->bind_param("ss", $CN, $CT);
$stmt->execute();
} catch (mysqli_sql_exception $e) {
if ($e->getCode() !== DUPLICATE_KEY) {
// if it failed for any other reason than duplicate key rethrow the exception
throw $e;
}
// if SQL failed due to duplicate entry then set the error message
$arr = [
'PASS' => "FAIL",
'MSG' => "Err: duplicate '$CN' '$CT' pair",
];
}
echo json_encode($arr);
} else {
header("location: ../Error_Fail.php");
}
Regarding performance.
There is no problem with performance in this example and prepared statements don't improve or degrade the performance. I assume you are trying to compare the performance to static SQL queries, but in your simple example there should be no difference at all. Prepared statements can make your code faster compared to static queries when you need to execute the same SQL many times.
If you find writing the 3 lines of code each time too much, then you can create a wrapper function that will reduce it for you to a single function call. In fairness you should avoid using mysqli on its own. Either switch to PDO or use some kind of abstraction library around mysqli.
Related
I need to show website visitor that something went wrong should him making queries to my database fails technically.
Want to get the php code to echo "Sorry! Something went wrong!" if for some reason data fetching failed.
Following are some ways I am trying to accomplish this.
3 samples.
They result in neverending loops thus crashing my browser.
(NOTE the IFs on each sample. That is where the 3 samples differ).
I ranked them according to favourite ....
How to fix this to bare minimum to achieve my purpose ? Would appreciate codes samples. I know how to achieve this with mysqli_stmt_get_result() but need to learn with the mysqli_stmt_bind_result() in procedural style programming. Not into oop yet. Nor pdo.
1.
<?php
//LOOPS NEVERENDING
$server = 'localhost';
$user = 'root';
$password = '';
$database = 'brute';
$conn = mysqli_connect("$server","$user","$password","$database");
$keywords = 'keyword';
$query = 'SELECT id,domain from links WHERE keywords = ?';
$stmt = mysqli_stmt_init($conn);
if(mysqli_stmt_prepare($stmt,$query))
{
mysqli_stmt_bind_param($stmt,'s',$keywords);
if(mysqli_stmt_execute($stmt))
{
while($result = mysqli_stmt_bind_result($stmt,$id,$domain))
{
mysqli_stmt_fetch($stmt);
echo 'Id: ' .$id; echo '<br>';
echo 'Domain: ' .$domain; echo '<br>';
if(!$result)
{
echo 'Sorry! Something went wrong. Try again later.';
}
}
}
mysqli_stmt_close($stmt);
mysqli_close($conn);
}
?>
<?php
//LOOPS NEVERENDING
$server = 'localhost';
$user = 'root';
$password = '';
$database = 'brute';
$conn = mysqli_connect("$server","$user","$password","$database");
$keywords = 'keyword';
$query = 'SELECT id,domain from links WHERE keywords = ?';
$stmt = mysqli_stmt_init($conn);
if(mysqli_stmt_prepare($stmt,$query))
{
mysqli_stmt_bind_param($stmt,'s',$keywords);
mysqli_stmt_execute($stmt);
while(mysqli_stmt_bind_result($stmt,$id,$domain))
{
if(mysqli_stmt_fetch($stmt)) //If 'Rows Fetching' were successful.
{
echo 'Id: ' .$id; echo '<br>';
echo 'Domain: ' .$domain; echo '<br>';
}
else //If 'Rows Fetching' failed.
{
echo 'Sorry! Something went wrong. Try again later.';
}
}
mysqli_stmt_close($stmt);
mysqli_close($conn);
}
?>
<?php
//LOOPS NEVERENDING
$server = 'localhost';
$user = 'root';
$password = '';
$database = 'brute';
$conn = mysqli_connect("$server","$user","$password","$database");
$keywords = 'keyword';
$query = 'SELECT id,domain from links WHERE keywords = ?';
$stmt = mysqli_stmt_init($conn);
if(mysqli_stmt_prepare($stmt,$query))
{
mysqli_stmt_bind_param($stmt,'s',$keywords);
if(mysqli_stmt_execute($stmt)) //If 'Query Execution' was successful.
{
while(mysqli_stmt_bind_result($stmt,$id,$domain))
{
mysqli_stmt_fetch($stmt);
echo 'Id: ' .$id; echo '<br>';
echo 'Domain: ' .$domain; echo '<br>';
}
}
else //If 'Query Execution' failed.
{
echo 'Sorry! Something went wrong. Try again later.';
}
mysqli_stmt_close($stmt);
mysqli_close($conn);
}
?>
Basically, all of the approaches are wrong. If the query fails then there will be an error triggered automatically by PHP as long as you have error reporting enabled, see How to get the error message in MySQLi?. You should not be checking for it manually. Your code is way longer than it needs to be. Consider how it should be done properly:
<?php
$server = 'localhost';
$user = 'root';
$password = '';
$database = 'brute';
// enable error reporting
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$conn = mysqli_connect($server, $user, $password, $database);
mysqli_set_charset($conn, 'utf8mb4');
$keywords = 'keyword';
$query = 'SELECT id,domain from links WHERE keywords = ?';
$stmt = mysqli_prepare($conn, $query);
mysqli_stmt_bind_param($stmt, 's', $keywords);
mysqli_stmt_execute($stmt);
mysqli_stmt_bind_result($stmt, $id, $domain);
// This loop will keep on going as long as fetch() returns true.
// It will return false when it reaches the end
while (mysqli_stmt_fetch($stmt)) {
echo 'Id: ' .$id;
echo '<br>';
echo 'Domain: ' .$domain;
echo '<br>';
}
When you enable mysqli error reporting, your code becomes much simpler. There's no need for any special message to the user. When a query fails then an error will be triggered just like any other PHP error and handled the same way. If you want you can then customize the error page, but that is a completely separate topic.
The loop on mysqli_stmt_fetch() is used to fetch the data from the server. The data will be read row by row, and when there are no more rows mysqli_stmt_fetch() will return false.
mysqli_stmt_bind_result() needs to be called only once. Its purpose is to provide variable placeholders into which the data will be populated.
Their is a mistake in your code that make your code loop forever. In such cases, a while loop in your code is one of the most common cause of this kind of problem.
When you are using any function you should consider to read the documentation of this function and check what kind of errors and what kind of results (returns) it can give you. Functions can throw errors, warning, Exceptions, or return error codes. Also dont underestimate examples on the PHP documentation of each function. It give you a good idea of how things works.
When you are calling a function it's generally good to check the result returned. I will not rewrite all the documentation here but here is an example for mysqli_stmt_bind_result :
https://www.php.net/manual/en/mysqli-stmt.bind-result.php
This part of the procedural example is important for you :
/* bind variables to prepared statement */
mysqli_stmt_bind_result($stmt, $col1, $col2);
/* fetch values */
while (mysqli_stmt_fetch($stmt)) {
printf("%s %s\n", $col1, $col2);
}
Here you can see how mysqli_stmt_bind_result and mysqli_stmt_fetch can be used together to loop through your results.
But this is not perfect for error checking.
The documentation of mysqli_stmt_bind_result says in section Return values :
Returns true on success or false on failure.
So in case of failure of this function you can check for errors this way :
if (!mysqli_stmt_bind_result($stmt, $id, $domain)) {
die("mysqli_stmt_bind_result has failed !"); // of course you can use something more sophisticated than dying...
}
In case of success, and the source of your infinite loop is here, it returns true. So doing while(mysqli_stmt_bind_result($stmt, $id, $domain)) is a mistake, first because you dont have to loop on this function (it's a job for mysqli_stmt_fetch), secondly because mysqli_stmt_bind_result will ever returns true in your case and your while loop will never end.
For mysqli_stmt_fetch now, there is a subtle difference. Check the return values : https://www.php.net/manual/en/mysqli-stmt.fetch.php
Return Value
Description
true
Success. Data has been fetched
false
Error occurred
null
No more rows/data exists or data truncation occurred
Here you have to check for 3 different values and dont forget that null and false can both be evaluated as falsy if you dont take care.
This doesnt allow to display an error :
while (mysqli_stmt_fetch($stmt)) { // is result false or null ? we dont know
printf ("%s (%s)\n", $id, $domain);
}
This is more complete :
$fetchResult = null;
while ($fetchResult = mysqli_stmt_fetch($stmt)) {
printf ("%s (%s)\n", $id, $domain);
}
/* dont forget to use 3 equal signs to also compare variable type */
/* null == false values are considered the same */
/* null === false this also compare variable types, here types are not the same */
if ($fetchResult === false) {
die("mysqli_stmt_fetch failed !");
}
Now you are free to read the documentation of all called functions to do your errors checks.
Also note that another error management (less verbose and error prone) is possible using Exceptions objects like explained by Dharman answer
I keep running into the error where PHP says "We're sorry we can't log you in." according to one of my conditions set even if login is correct and hence my Prepared system to avoid SQL injection fails.
So my code goes like this:
global $connected;
$post = filter_var_array($_POST, FILTER_SANITIZE_STRING);
$pwwd = $post['password'];
$usrn = $post['username'];
$usrn = mysqli_real_escape_string($connected, $usrn);
$pwwd = mysqli_real_escape_string($connected, $pwwd);
if (strlen($usrn) != 0 && strlen($pwwd) != 0 && !empty($post)) {
$usrn = stripslashes($usrn);
$pwwd = stripslashes($pwwd);
$hashFormat = '$2ysomenumber$';
$salt = 'somehashobviously';
$hashF_and_salt = $hashFormat.$salt;
$pwwd = crypt($pwwd, $hashF_and_salt);
if (!mysqli_connect_errno()) {
mysqli_select_db($connected, 'someDbname') or die('Database select error');
} else {
die('Failed to connect to PHPMyAdmin').mysqli_connect_error();
}
$query = "SELECT Username, Password FROM users WHERE Username=? AND Password=?";
$stmt = mysqli_stmt_init($connected);
if (mysqli_stmt_prepare($stmt, $query)) {
//Some error in here somewhere
mysqli_stmt_bind_param($stmt, "ss", $usrn, $pwwd);
mysqli_stmt_execute($stmt);
mysqli_stmt_fetch($stmt);
mysqli_stmt_bind_result($stmt, $check_usrn, $check_pwd);
if (strcasecmp($usrn, $check_usrn) == 0) {
if ($pwwd == $check_pwd) {
echo '<h1 class="text-center">Matches</h1>';
print_r($row);
}
} else {
echo "<h1 class=text-center>We're sorry we can't log you in.</h1>";
}
}
} else { //This is for strlen boolean cond
echo "<h1 class='text-center'>Both fields must not be empty. </h1>";
}
I used to use a login page without prepared statements which was working, but I realised I need to do this for better security. My database is working fine so the problem is near where I added the comment "//Some error in here somewhere".
I am a relatively new PHP programmer that is yet a first year student trying daring new things in the holidays! Will openly read all the help I get, thank you!
First i didn't see your connection code for connection to the database which is like this.
$connected = msqli_connect(host,user,password,db_name) ; than you don't need to call mysqli_select_db()function.
Secondly you are checking your connectinon from mysqli_connect_errno() function which return 0 as integer (not boolean) if no error code value for last mysqli_connect() function.
Third there is no need to Initializes prepare statement.
Fourth is mysqli_stmt_bind_reslut() comes before the mysqli_stmt_fetch(). see note point in manual
Use hash_equals() function to match password instead of ===. see the warning section in crypt
$connected = msqli_connect(host,user,password,db_name) ;
if(!$connected)
{
die('Connect Error (' . mysqli_connect_errno() . ') '. mysqli_connect_error());
}
echo "Your connection is successful . "
if($stmt = mysqli_prepare($connected,$query))
{
mysqli_stmt_bind_param($stmt, "ss", $usrn, $pwwd);
mysqli_stmt_execute($stmt);
mysqli_stmt_bind_result($stmt, $check_usrn, $check_pwd);
mysqli_stmt_fetch($stmt);
/* Now do Your Work */
} else
{
/* still prepare statement doesn't work */
} `
I have a problem when i try to check if email is alredy registered. can someone help? I have this error:
mysql_fetch_array(): supplied argument is not a valid MySQL result resource in line...
($record =mysql_fetch_array($result); )
<?php
$nome = $_REQUEST["nome"];
$cognome = $_REQUEST["cognome"];
$psw = $_REQUEST["psw"];
$email = $_REQUEST["email"];
$nikName = $_REQUEST["nikName"];
$conn = mysql_connect("host,name","userName","Password","databaseName");
if(!$conn) {
echo "connessione non satabilita";
} else {
if(!mysql_select_db("databaseName",$conn)) {
echo "database non trovato";
} else {
$sql = "select * from utenti where User='$email'"; //costruzione comando di ricerca
$result = mysql_query($sql,$conn); //assegnazione risultati
$record =mysql_fetch_array($result); //estrazione primo risultato
if(!$record) {
$sql = "INSERT INTO User (UserId, Nome, Cognome, Email, Username, Password, TimeStamp) VALUES (NULL,'$nome','$cognome','$email','$nikName','$psw', NULL)";
$result=mysql_query($sql);
if($result) {
echo "utente registrato correttamente";
} else {
//Error
echo "errore registrazione, riprovare più tardi";
}
echo "<br />";
echo "utente registrato";
} else {
echo "utente gia registrato";
}
}
}
?>
Before this gets out of hand.
$conn = mysql_connect("host,name","userName","Password","databaseName");
You're using 4 parameters rather than 3.
Sidenote: 4 parameters is mysqli_ syntax http://php.net/manual/en/function.mysqli-connect.php
Be careful though, those different MySQL APIs do not intermix. So you cannot have mysql_ with mysqli_ should you decide to change it to that.
The manual http://php.net/manual/en/function.mysql-connect.php states:
$link = mysql_connect('localhost', 'mysql_user', 'mysql_password');
the fourth is for something else.
If a second call is made to mysql_connect() with the same arguments, no new link will be established, but instead, the link identifier of the already opened link will be returned. The new_link parameter modifies this behavior and makes mysql_connect() always open a new link, even if mysql_connect() was called before with the same parameters. In SQL safe mode, this parameter is ignored.
So, just remove the 4th parameter.
Sidenote: This is questionable "host,name" (with the comma). Double check it as to what your host (if hosted) has provided you with. Most of the time, that should read as "localhost".
As stated, you're open to SQL injection.
Use a prepared statement:
https://en.wikipedia.org/wiki/Prepared_statement
As for the rest of your code:
Add error reporting to the top of your file(s) which will help find errors.
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
// rest of your code
Sidenote: Displaying errors should only be done in staging, and never production.
Also add or die(mysql_error()) to mysql_query().
About you're wanting to check if an email exists; you may be better off using mysql_num_rows().
I.e.:
$sql = "select * from utenti where User='$email'";
$result = mysql_query($sql,$conn) or die(mysql_error($conn));
if(mysql_num_rows($result) > 0)
{...}
else {...}
I noticed you may be storing passwords in plain text. If this is the case, it is highly discouraged.
I recommend you use CRYPT_BLOWFISH or PHP 5.5's password_hash() function. For PHP < 5.5 use the password_hash() compatibility pack.
Also, this doesn't help you:
if(!mysql_select_db("databaseName",$conn)){
echo "database non trovato";
}
This does:
if(!mysql_select_db("databaseName",$conn)){
die ('Can\'t use the database : ' . mysql_error());
}
In order to get the real error, should there be one.
Reference:
http://php.net/manual/en/function.mysql-select-db.php
As mentioned above there is a syntax error with mysql_connect(); where you're trying to use invalid number of params. The best way is to make a config.php file and then use it whenever you need it. This is a basic connection code in PDO.
<?php
$host = "localhost";
$database = "yourdbnamehere";
$username = "yourusernamehere";
$password = "yourpasswordhere";
try {
$dbo = new PDO('mysql:host='.$host.';dbname='.$database, $username, $password);
} catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "<br/>";
die();
}
?>
You will need a solution like this. But you must switch towards PDO or MySQLi to ensure that your code stays valid in long run as well as you will be able to write secure and stable code.
Go through these at first:
http://php.net/manual/en/book.pdo.php
http://php.net/manual/en/book.mysqli.php
An example code for you solving your current problem:
<?php
$nome = $_REQUEST["nome"];
$cognome = $_REQUEST["cognome"];
$psw = $_REQUEST["psw"];
$email = $_REQUEST["email"];
$nikName = $_REQUEST["nikName"];
try{
$pdo = new PDO('mysql:dbhost=hostname; dbname=databaseName', 'userName', 'Password');
} catch (PDOException $e) {
echo "Error connecting to database with error ".$e;
die();
}
// check for email
$sql = $pdo->prepare("select * from utenti where User= ?");
$sql->bindParam('1', $email);
$sql->execute();
/* if you aren't hashing the password,
then do it first
$psw = PASSWORD_HASH($psw, PASSWORD_DEFAULT);
*/
// Insert if email not registered
if($sql->rowCount() == 0) {
$insert = $pdo->prepare("INSERT INTO User (Nome,Cognome,Email,Username,Password) VALUES (?, ?, ?, ?, ?)");
$insert->bindParam('1', $nome);
$insert->bindParam('2', $cognome);
$insert->bindParam('3', $email);
$insert->bindParam('4', $nikName);
$insert->bindParam('5', $psw);
$insert->execute();
if($insert->rowCount() > 0) {
echo "utente registrato correttamente";
} else {
echo "errore registrazione, riprovare più tardi";
}
} else {
echo "utente gia registrato";
}
?>
I just switched to PDO from mySQLi (from mySQL) and it's so far good and easy, especially regarding prepared statements
This is what I have for a select with prepared statement
Main DB file (included in all pages):
class DBi {
public static $conn;
// this I need to make the connection "global"
}
try {
DBi::$conn = new PDO("mysql:host=$dbhost;dbname=$dbname;charset=utf8", $dbuname, $dbpass);
DBi::$conn->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
DBi::$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e) {
echo '<p class="error">Database error!</p>';
}
And in my page:
try {
$sql = 'SELECT pagetitle, pagecontent FROM mypages WHERE pageid = ? LIMIT 1';
$STH = DBi::$conn->prepare($sql);
$STH->execute(array($thispageid)); // $thispageid is from a GET var
}
catch(PDOException $e) {
echo '<p class="error">Database query error!</p>';
}
if ($STH) { // does this really need an if clause for it self?
$row = $STH->fetch();
if (!empty($row)) { // was there found a row with content?
echo '<h1>'.$row['pagetitle'].'</h1>
<p>'.$row['pagecontent'].'</p>';
}
}
It all works. But am I doing it right? Or can I make it more simple some places?
Is using if (!empty($row)) {} an ok solution to check if there was a result row with content? Can't find other decent way to check for numrows on a prepared narrowed select
catch(PDOException $e) {
echo '<p class="error">Database query error!</p>';
}
I would use the opportunity to log which database query error occurred.
See example here: http://php.net/manual/en/pdostatement.errorinfo.php
Also if you catch an error, you should probably return from the function or the script.
if ($STH) { // does this really need an if clause for it self?
If $STH isn't valid, then it should have generated an exception and been caught previously. And if you had returned from the function in that catch block, then you wouldn't get to this point in the code, so there's no need to test $STH for being non-null again. Just start fetching from it.
$row = $STH->fetch();
if (!empty($row)) { // was there found a row with content?
I would write it this way:
$found_one = false;
while ($row = $STH->fetch()) {
$found_one = true;
. . . do other stuff with data . . .
}
if (!$found_one) {
echo "Sorry! Nothing found. Here's some default info:";
. . . output default info here . . .
}
No need to test if it's empty, because if it were, the loop would exit.
I tried updating my data like so but it doesn't work
<?php
require("config.inc.php");//this piece of code us for authentication and it works fine.
if(!empty($_POST))
{
/**
the values below in the POST are valid not empty values
**/
$shell = $_POST['shell'];
$reporter = $_POST['reporter'];
//query
$query = "UPDATE `shellingdb`
SET `likes` = `likes` + 1
WHERE `shell` = :shell AND `reporter` = :reporter";
try {
$query_params = array(':shell' => $_POST['shell'], ':reporter' => $_POST['reporter']);//Updates likes
$stmt = $db->prepare($query);
$result = $stmt->execute($query_params);
$affected = $stmt->rowCount();//counts the number of affected rows during the update query
if($affected > 0)
{
$response["success"] = 1;
$response["message"] = "Updated! this number of rows were affected".$affected;
echo json_encode($response);
}else
{
$response["success"] = 2;
$response["message"] = "Not Updated! huh!".$affected;
echo json_encode($response);
}
}
catch (Exception $ex) {
$response["success"] = 0;
$response["message"] = "Database Error!".$ex->getMessage();
die(json_encode($response));
}
}
?>
the config.inc.php
<?php
// These variables define the connection information for your MySQL database
$username = "xmnj3jh0jhtheu_14265914";
$password = "jhikjskjiavethew";
$host = "sqlkjnlkkjlk101.x3kuhiu0lkj.us";
$dbname = "x3lnklj0u_1426jbkb5914_gbabbjkhjajhlert";
// UTF-8 is a character encoding scheme that allows you to conveniently store
// a wide varienty of special characters, like � or �, in your database.
// By passing the following $options array to the database connection code we
// are telling the MySQL server that we want to communicate with it using UTF-8
// See Wikipedia for more information on UTF-8:
// http://en.wikipedia.org/wiki/UTF-8
$options = array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8');
// A try/catch statement is a common method of error handling in object oriented code.
// First, PHP executes the code within the try block. If at any time it encounters an
// error while executing that code, it stops immediately and jumps down to the
// catch block. For more detailed information on exceptions and try/catch blocks:
// http://us2.php.net/manual/en/language.exceptions.php
try
{
// This statement opens a connection to your database using the PDO library
// PDO is designed to provide a flexible interface between PHP and many
// different types of database servers. For more information on PDO:
// http://us2.php.net/manual/en/class.pdo.php
$db = new PDO("mysql:host={$host};dbname={$dbname};charset=utf8", $username, $password, $options);
}
catch(PDOException $ex)
{
// If an error occurs while opening a connection to your database, it will
// be trapped here. The script will output an error and stop executing.
// Note: On a production website, you should not output $ex->getMessage().
// It may provide an attacker with helpful information about your code
// (like your database username and password).
die("Failed to connect to the database: " . $ex->getMessage());
}
// This statement configures PDO to throw an exception when it encounters
// an error. This allows us to use try/catch blocks to trap database errors.
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// This statement configures PDO to return database rows from your database using an associative
// array. This means the array will have string indexes, where the string value
// represents the name of the column in your database.
$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
// This block of code is used to undo magic quotes. Magic quotes are a terrible
// feature that was removed from PHP as of PHP 5.4. However, older installations
// of PHP may still have magic quotes enabled and this code is necessary to
// prevent them from causing problems. For more information on magic quotes:
// http://php.net/manual/en/security.magicquotes.php
if(function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc())
{
function undo_magic_quotes_gpc(&$array)
{
foreach($array as &$value)
{
if(is_array($value))
{
undo_magic_quotes_gpc($value);
}
else
{
$value = stripslashes($value);
}
}
}
undo_magic_quotes_gpc($_POST);
undo_magic_quotes_gpc($_GET);
undo_magic_quotes_gpc($_COOKIE);
}
// This tells the web browser that your content is encoded using UTF-8
// and that it should submit content back to you using UTF-8
header('Content-Type: text/html; charset=utf-8');
// This initializes a session. Sessions are used to store information about
// a visitor from one web page visit to the next. Unlike a cookie, the information is
// stored on the server-side and cannot be modified by the visitor. However,
// note that in most cases sessions do still use cookies and require the visitor
// to have cookies enabled. For more information about sessions:
// http://us.php.net/manual/en/book.session.php
session_start();
// Note that it is a good practice to NOT end your PHP files with a closing PHP tag.
// This prevents trailing newlines on the file from being included in your output,
// which can cause problems with redirecting users.
?>
don't know what's wrong and it gives no error it goes into the else statement, meaning the values were not updated. i tried the same code in sqlfiddle and it works but not in my PhpMyAdmin.
I know the updated value is supposed to be passed into the $query_params but am incrementing the value of likes each time it is run, and am not sure how to do that in the $query_params unless i use a seperate query to get the numberof likes and then increament it but that could be costly.
Query without PDO still it does not work this time it give update unsuccessful
<?php
$username = "x3jbhiukhkj0u426jbhjnbvh591mbhb4";
$password = "savjiuejbiuhilkmthljiew";
$host = "sqlnjhbjhnkjjjhbj";
$dbname = "x3hjbh0ukjioiuhgbjhvhgvh";
$shell = "Rustig";
$reporter = "davies";
//query
$query = "UPDATE `shellingdb`
SET `favs` = 1
WHERE `shell` = 'Rustig'";
$link = mysql_connect($host, $username, $password);
if (!$link)
{
die('Could not connect: ' . mysql_error());
}else
{
echo 'Connected successfully';
$db_selected = mysql_select_db($dbname, $link);
if (!$db_selected)
{
die ('Can\'t use foo : ' . mysql_error());
}else
{
echo 'Connected to database successfully';
if(empty($_POST))
{
$retval = mysql_query( $query, $link )or die(mysql_error($link));;
if(! $retval )
{
die('Could not query database: ' . mysql_error());
}else
{
if(mysql_affected_rows() > 0)
{
echo "Updated data successfully\n";
}else
{
//echo "shell=".$shell." reporter=".$reporter';
echo "Updated data Unsuccessfully\n";
}
}
}
}
}
mysql_close($link);
?>
The below is the output of the PDOStatement::debugDumpParams(); for the first php syntax
SQL: [124] UPDATE shellingdb SET likes = likes + 1 WHERE shell = :shell AND reporter >= :reporter Params: 2 Key: Name: [6] :shell paramno=-1 name=[6] ":shell" is_param=1 param_type=2 Key: Name: [9] :reporter paramno=-1 name=[9] ":reporter" is_param=1 param_type=2
I used bindParam. bindParam is a method on PDOStatement.
Try:
<?php
require("config.inc.php");//this piece of code us for authentication and it works fine.
if(isset($_POST))
{
/**
the values below in the POST are valid not empty values
**/
$shell = $_POST['shell'];
$reporter = $_POST['reporter'];
//query
$query = "UPDATE `shellingdb`
SET `likes` = `likes` + 1
WHERE `shell` = :shell AND `reporter` = :reporter";
try {
$stmt = $db->prepare($query);
$stmt->bindParam(":shell", $shell);
$stmt->bindParam(":reporter", $reporter);
$stmt->execute();
$affected = $stmt->rowCount();//counts the number of affected rows during the update query
if($affected > 0)
{
$response["success"] = 1;
$response["message"] = "Updated! this number of rows were affected".$affected;
echo json_encode($response);
}else
{
$response["success"] = 2;
$response["message"] = "Not Updated! huh!".$affected;
echo json_encode($response);
}
}
catch (Exception $ex) {
$response["success"] = 0;
$response["message"] = "Database Error!".$ex->getMessage();
die(json_encode($response));
}
}
?>
some how, after long hours of try and error(Brut Forcing) this finally worked
$query = "UPDATE `shellingdb` SET `likes`=`likes`+1 WHERE `shell` = :shell AND `reporter` = :reporter";
Thanks all those who tried to help. :)