I just converted some MySQL to mysqli, but realized I do not have access to the mysqlnd driver with my server setup. So, I need to now convert to PDO which I have available.
I am trying to convert the following to PDO, but there is no bind_result available in PDO from what I have read. I need to use a prepared statement for this as there is user input.
$stmt = $mysqli->prepare("SELECT user,pass FROM test_users WHERE user = ?");
// bind params
$stmt->bind_param('s', $_POST['username']);
// execute prepared statement
$stmt->execute();
// Bind result variables
$stmt->bind_result($ruser, $rpass);
// fetch values
$stmt->fetch();
// close statement
$stmt->close();
Can anyone help out quick? Here is what I have, but not sure how to retrieve the resulting values into useable variables...
$stmt = $db->prepare("SELECT user,pass FROM test_users WHERE user = ?");
// bind params
$value = $_POST['username'];
// execute prepared statement
$stmt->execute($value);
// stmt now holds results, but how can I retrieve them into useable values?
// ?
// close statement
$stmt->closeCursor();
You need to make yourself familiar with arrays. They are no less "useable" than regular variables.
And sometimes arrays even more usable, especially in your case.
$stmt = $db->prepare("SELECT user, pass FROM test_users WHERE user = ?");
$stmt->execute([$_POST['username']]);
$row = $stmt->fetch();
Now $row contains the row returned by query. Now you can test if any data returned and then use it.
For the password check you can use it this way
if ($row && $row['pass'] === whatever_hash_used($_POST['password']]))
{
unset($row['pass']);
$_SESSION['user'] = $row;
// etc
}
You can return values from a PDO query with the PDOStatement::fetch method. There are various ways of fetching the data, such as into an array, into an object, and into a lazy-loading object. The simplest of these, and the most appropriate in your circumstance, is an array. In this case, you need to use the PDO::FETCH_ASSOC constant.
$results = $stmt->fetch(PDO::FETCH_ASSOC);
You can then access $results['user'] and $results['pass'].
A nice way of improving this would be to fetch $user and $pass variables rather than an array. This can be done with the list construct:
list($user, $pass) = $stmt->fetch(PDO::FETCH_NUM);
The other problem with your code (as Your Common Sense may or may not be pointing out in the comments: it's a little hard to tell) is that your code to bind the variables isn't quite right. PDOStatement::execute expects an array:
$stmt->execute(array($value));
$stmt->execute([$value]); // from PHP 5.4
In my opinion, the nicer way to do this is with named parameters:
$stmt = $db->prepare('SELECT user, pass FROM test_users WHERE user = :user');
$stmt->bindParam(':user', $_POST['username']);
$stmt->execute();
list($user, $pass) = $stmt->fetch(PDO::FETCH_NUM);
Related
So I have a MySQL database and would like to create variables from that database that I can use in HTML code.
For example if I use <video blablabla some stuff src="phpVariable" /video>
I don't want to have a static URL in the HTML code. It should be assigned to a variable based on an SQL query. What is the best way to do this?
First, you need to retrieve the data from the database that you wish to use, using a database query. From there, you can loop through all the results and output them.
Replace 'tablename' with the name of the database table and 'columnName' with the column name.
$con should be used to connect to your database. See https://www.php.net/manual/en/pdo.connections.php
$stmt = $con->prepare("SELECT * FROM tablename");
$stmt->execute();
while($row = $stmt->fetch()) {
echo $row['columnName'];
}
If you only needed to retrieve one record, change the code to:
$stmt = $con->prepare("SELECT * FROM tablename");
$stmt->execute();
$row = $stmt->fetch();
echo $row['columnName'];
You can also store the retrieved data as a variable, like this:
$variableName = $row['columnName'];
// Then to use the variable in your code:
echo'<video src='.$variableName.'</video>';
This is very basic PHP though. Have you looked at some online guides?
sub completecheckout {
$cryptedcard = md5_hex($cardnum . $salt);
$grabcart = qq~select pid from cart where uid='$cookievalue'~;
$dbh = DBI->connect($connectionInfo, $user, $passwd);
$sth = $dbh->prepare($grabcart);
$sth->execute();
while (#row = $sth->fetchrow_array()) {
$insert = qq~insert transaction (uid, pid, cctype, ccnum)
values ('$cookievalue', '$row[0]', '$cardtype',
'$cryptedcard')~;
$dbh = DBI->connect($connectionInfo, $user, $passwd);
$sth = $dbh->prepare($insert);
$sth->execute();
}
$select = qq~select * from registered where id in
(select uid from transaction
where uid='$cookievalue')~;
$dbh = DBI->connect($connectionInfo,$user,$passwd);
$sth = $dbh->prepare($select);
$sth->execute();
#userinfo = $sth->fetchrow_array();
print header;
print qq~<html><head><title>YAY</title></head><body><p>CHECK MYSQL<p><p>#row</p></body></html>~;
}
I am trying to parse through the table cart and insert all the items associated with the user into a transaction table when they click the final checkout button. The above code will only insert the last row into the transaction table.
Here is code that inserts more than once, but does not work because $product is empty every other time.
sub completecheckout {
$cryptedcard = md5_hex($cardnum . $salt);
$grabcart = qq~select pid from cart where uid='$cookievalue'~;
$dbh = DBI->connect($connectionInfo,$user,$passwd);
$sth = $dbh->prepare($grabcart);
$sth->execute();
#cart = $sth->fetchrow_array();
foreach $product (#cart) {
$insert = qq~insert transaction (uid, pid, cctype, ccnum)
values ('$cookievalue', '$product', '$cardtype',
'$cryptedcard')~;
$dbh = DBI->connect($connectionInfo,$user,$passwd);
$sth = $dbh->prepare($insert);
$sth->execute();
}
$select = qq~select * from registered where id in
(select uid from transaction
where uid='$cookievalue')~;
$dbh = DBI->connect($connectionInfo,$user,$passwd);
$sth = $dbh->prepare($select);
$sth->execute();
#userinfo = $sth->fetchrow_array();
print header;
print qq~<html><head><title>YAY</title></head><body><p>CHECK MYSQL<p><p>#userinfo</p></body></html>~;
}
Can anyone explain why this happens? I have been using while loops with fetchrow_array throughout my script to create tables linked to databases.
Firstly, you need to get into the habit of formatting your code better. It really helps following logic flow if the formatting imitates the logic.
Secondly, please turn on use strict and get used to declaring variables as close to their point of use as possible.
Thirdly, don't use global variables. Your subroutine uses $cardnum, $salt, $cookievalue and several other variables which are (presumably) defined outside of the subroutine. They should all be passed into the subroutine as parameters.
I know from previous conversations that you have no interest in learning Perl, you're just trying to get through a course that your college insists on. So I should make it clear that all of the advice above has nothing to do with Perl. That is all good general advice for any programming language.
Now, the specific problems.
You're creating a new $dbh any time you want to run a database query. Why not just connect once and then reuse that variable. A single $dbh can support multiple queries executing at the same time.
As Matt has pointed out in the comments, you are overwriting $sth. As I said above, a $dbh can support multiple concurrent queries, but each query needs its own statement handle. So you might do something like:
my $dbh = DBI->connect(...);
my $select_sth = $dbh->prepare($select_sql);
$select_sth->execute;
while (my #row = $select_sth->fetchrow_array) {
my $insert_sth = $dbh->prepare($insert_sql);
$insert_sth->execute;
}
Notice how I've a) reused the same $dbh and b) declared the $insert_sth within the loop so it's only available for the shorted possible amount of time.
If you were interested in Perl, I'd also show you how to make your code more efficient by using bind points in your SQL and passing extra parameters to execute(). I'd also recommend moving raw HTML out of your program and using a templating engine. But I strongly suspect you wouldn't be interested.
Alright, so I believe that there is a better way that I can fetch an array from the database, here's the code right now that I have.
$id = 1;
$userquery = mysql_query("SELECT * FROM login WHERE id='$id'");
while($row = mysql_fetch_array($userquery, MYSQL_ASSOC)) {
$username = $row['username'];
$password = $row['password'];
$email = $row['email'];
}
So If I am not wrong, you want a better way to get all the returned rows from mysql in a single statement, instead of using the while loop.
If thats the case, then I must say mysql_ drivers do not provide any such functionality, which means that you have to manually loop through them using foreach or while.
BUT, since mysql_ is already depricated, you are in luck! you can actually switch to a much better and newer mysqli_ or the PDO drivers, both of which DO actually have functions to get all the returned rows.
For mysqli_: mysqli_result::fetch_all
For PDO : PDOStatement::fetchAll
Eg.
mysqli_fetch_all($result,MYSQLI_ASSOC);
// The second argument defines what type of array should be produced
// by the function. `MYSQLI_ASSOC`,`MYSQLI_NUM`,`MYSQLI_BOTH`.
Like the comments already told you: PHP's mysql driver is deprecated. And you should use prepared statements and parameters.
for example in PDO your code would look something like this:
//connection string:
$pdo= new PDO('mysql:host=localhost;dbname=my_db', 'my_user', 'my_password');
//don't emulate prepares, we want "real" ones:
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
//use exception-mode if you want to use exception-handling:
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$id = 1;
//it's always better to strictly use backticks for db-names (db, tables, fields):
$sql = "SELECT * FROM `login` WHERE `id` = :id";
try
{
//create your prepared statement:
$stmt = $pdo->prepare($sql);
//bind a parameter and explicitly use a parameter of the type integer (in this case):
$stmt->bindParam(":id", $id, PDO::PARAM_INT);
//execute the query
$stmt->execute();
}
catch(PDOException $e)
{
exit("PDO Exception caught: " . $e->getMessage());
}
while($row = $stmt->fetch(PDO::FETCH_ASSOC))
{
$username = $row['username'];
$password = $row['password'];
$email = $row['email'];
}
here you go: your PHP-MySQL routine is save against SQL-injections now and no longer uses deprecated PHP-functions! it's kinda state of the art ;)
I want to build the below query using joomla inbuilt database class.
SELECT *
FROM table_name
ORDER BY id DESC
LIMIT 1
This is the query I have built up to now.
$db =& JFactory::getDBO();
$query = $db->getQuery(true);
$query->select($db->nameQuote('*'));
$query->from($db->nameQuote(TABLE_PREFIX.'table_name'));
$db->setQuery($query);
$rows = $db->loadObjectList();
I don't know how to add the limit(LIMIT 1) to the query. Can someone please tell me how to do it? Thanks
Older than Joomla 3.0
$db = JFactory::getDBO();
$query = $db->getQuery(true);
$query->select('*')
->from($db->nameQuote('#__table_name'))
->order($db->nameQuote('id').' desc');
$db->setQuery($query,0,1);
$rows = $db->loadObjectList();
$db->setQuery function takes 3 parameters. The first one being the query, then the start, then the limit. We can limit records as shown above.
Newer than Joomla 3.0
setLimit(integer $limit, integer $offset)
If you want just one row
$query->setLimit(1);
Read more
This should work as well:
$query->setLimit(1);
Documentation: http://api.joomla.org/cms-3/classes/JDatabaseQueryLimitable.html
SetLimit doesn't work for me in Joomla 3.4.x, so try:
Within the model:
protected function getListQuery()
{
// Create a new query object.
$db = JFactory::getDBO();
$query = $db->getQuery(true);
// Select some fields
$query->select('*');
$query->from('#__your_table');
$this->setState('list.limit', 0); // 0 = unlimited
return $query;
}
Davids answer: https://joomla.stackexchange.com/questions/4249/model-getlistquery-fetch-all-rows-with-using-jpagination
Run that before the model calls getItems and it will load all the
items for you.
A few caveats with this.
You can also do this outside the model, so if for instance you were in
your view. You could do the following:
$model = $this->getModel(); $model->setState('list.limit', 0);
Sometimes you can do this too early, before the model's state has been
populated, which will cause the model to get rebuilt from the user
state after you have set the limit, basically overriding the limit.
To fix this, you can force the model to populate its state first:
$model = $this->getModel(); $model->getState();
$model->setState('list.limit', 0); The actual populateState method is
protected, so outside the model you can't call it directly, but any
call to getState will make sure that the populateState is called
before returning the current settings in the state.
Update: Just had to revisit this answer, and I can confirm, both the methods
setLimit & order are working if used as below.
$query->order($db->qn($data->sort_column_name) . ' ' . $data->sort_column_order);
$query->setLimit($length,$start);
OLD ANSWER
As of 08/Sept/14 The solutions from #Dasun or #escopecz arent working for me on J3.x
but this old trick is working for me which is nice,
$query->order($db->qn('id') . ' DESC LIMIT 25');
And About your specific requirement of wishing to fetch only 1 row you could use :
$rows = $db->loadObject();
mysql_real_escape_string is preventing the unsanitized fields with bad characters from being added to the database. I don't want to have to specify all the fields on each form (since that's both cumbersome to do for each field and doesn't accommodate special characters which people may include or typos), but at the moment this code prevents anything from being inserted if any threatening characters are present in the unsanitized fields but still advances to the next page.
I'm also using jQuery validate on this page, but haven't been able to use that to prevent SQL injection.
function clean($str) {
$str = #trim($str);
if(get_magic_quotes_gpc()) {
$str = stripslashes($str);
}
return mysql_real_escape_string($str);
}
//Sanitize the POST values
$user_name = clean($_POST['user_name']);
$password = clean($_POST['password']);
//Create INSERT query
$qry = "INSERT INTO customer_info(fname, lname, gender, zip, email, phone, terms, security_question, security_answer, participating_retailers, notify_new_items, notify_promotions, priority1, priority2, priority3, priority4, priority5, privacy, user_name, password)
VALUES('$_POST[fname]','$_POST[lname]','$_POST[gender]','$_POST[zip]','$_POST[email]','$_POST[phone]','$_POST[terms]','$_POST[security_question]','$_POST[security_answer]','$_POST[participating_retailers]','$_POST[notify_new_items]','$_POST[notify_promotions]','$_POST[priority1]','$_POST[priority2]','$_POST[priority3]','$_POST[priority4]','$_POST[priority5]','$_POST[privacy]','$user_name','$password')";
$result = #mysql_query($qry);
$qry="SELECT * FROM customer_info WHERE user_name='$user_name' AND password='$password'";
$result=mysql_query($qry);
session_regenerate_id();
$member = mysql_fetch_assoc($result);
$_SESSION['SESS_USER_ID'] = $member['user_id'];
$_SESSION['SESS_FIRST_NAME'] = $member['fname'];
$_SESSION['SESS_LAST_NAME'] = $member['lname'];
session_write_close();
header("location: flatter-form.html");
exit();
mysql_query has been deprecated. PDO or mysqli both provide security against SQL injections. In addition to both having escaping functionality, PDO has the ability to also quote the string. Using prepared and parameterized queries makes it almost impossible for an attacker to inject SQL.
$stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name');
$stmt->execute(array(':name' => $name));
foreach ($stmt as $row) {
// do something with $row
}
Sample from: Prepared statements
Take a look at PDO vs. MySQLi.