Parameterized Queries - php

I am currently learning parametrized queries as there are advantages to using them.
Could someone give some pointers by converting this block of code to a parametrized version?
Thanks.
if(isset($_GET['news_art_id']) && (!empty($_GET['news_art_id'])))
{
$news_art_id = htmlentities(strip_tags($_GET['news_art_id']));
$news_art_id = validate_intval($news_art_id);
//echo $news_art_id;
$_SESSION['news_art_id'] = $news_art_id;
// Assign value to status.
$onstatus = 1;
settype($onstatus, 'integer');
$query = 'SELECT M.id, M.j_surname, M.j_points_count, M.j_level, A.j_user_id,A.id, A.jart_title, A.jart_tags, A.jart_description, A.jart_createddate FROM jt_articles A, jt_members M WHERE M.id = A.j_user_id AND A.id = ' . check_db_query_id($news_art_id) . " AND A.jart_status = $onstatus;";
$result = mysql_query($query) or die('Something went wrong. ' . mysql_error());
$artrows = mysql_num_rows($result);
}

The general rule is: Every variable should be binded, no inline variables at all.
Technical details: http://php.net/manual/en/pdo.prepare.php

in your case there is no advantage, remember a parameterised query requires 2 calls to the db : one to setup the query template and parse, the other to populate the query template params and is typically used when looping. So in this instance you're better off calling a stored procedure (always the best choice) or using inline sql and making sure you use http://php.net/manual/en/function.mysql-real-escape-string.php when applicable.

Related

MYSQL & PHP trouble with echoing tables

So I am trying to echo out how many rows there are in a table with a COUNT command, but I purposely have no rows in the table right now to test the if statement, and it is not working, but worst, it makes the rest of the site not work(the page pops up but no text or numbers show up on it), when I added a row to the table, it worked fine, no rows = no work. Here is the piece of the code that doesn't work. Any and all help is highly appreciated.
$query1 = mysql_query("
SELECT *, COUNT(1) AS `numberofrows` FROM
`table1` WHERE `user`='$username' GROUP BY `firstname`,`lastname`
");
$numberofrowsbase = 0;
while($row = mysql_fetch_assoc($query1))
{
if(isset($row['numberofrows']))
{
$enteries1 = $enteries1;
}else{
$enteries1 = $numberofrowsbase;
}
echo enteries1;
}
Seems you have over complicated everything. Some good advise from worldofjr you should take onboard but simplest way to get total rows from a table is:
SELECT COUNT(*) as numberofrows FROM table1;
There are several other unnecessary lines here and the logic is all bonkers. There is really no need to do
$enteries1 = $enteries1;
This achieved nothing.
Do this instead:
while($row = mysql_fetch_assoc($query1))
{
if(isset($row['numberofrows']))
{
echo $row['numberofrows'];
}
}
Maybe against my better judgement, I'm going to try and give you an answer. There's so many problems with this code ...
Do Not Use mysql_
The mysql_ extension is depreciated. You should use either mysqli_ or PDO instead. I'm going to use mysqli_ here.
SQL Injection
Your code is wide open to SQL injection where others can really mess up your database. Read How can I prevent SQL injection in PHP? for more information.
The Code
You don't need to count the rows with a SQL function, especially if you want to do something else with the data you're getting with the query (which I assume you are since you're getting a count on top of all the columns.
In PHP, you can get how many rows are in a result set using a built in function.
So all those things together. You should use something like this;
// Connect to the database
$mysqli = new mysqli($host,$user,$pass,$database); // fill in your connection details
if ($mysqli->connect_errno) echo "Error - Failed to connect to database: " . $mysqli->connect_error;
if($query = $mysqli->prepare("SELECT * FROM `table1` WHERE `user`=?")) {
$query->bind_param('s',$username);
$query->execute();
$result = $query->get_result();
echo $result->num_rows;
}
else {
echo "Could not prepare query: ". $mysqli->error;
}
The number of rows in the result is now saved to the variable $result->num_rows, so you can use just echo this if you want, like I have in the code above. You can then go onto using any rows you got from the database. For example;
while($row = $result->fetch_assoc()) {
$firstname = $row['firstname'];
$lastname = $row['lastname'];
echo "$firstname $lastname";
}
Hope this helps.

PHP MYSQL syntax

I'm having a little trouble with my MYSQL query
I have a DB full of products and I have a dropdown menu which lets a user select what time of day they'd like to get get results for :-
Dropdown
Breakfast
Lunch
Evening
Anytime
At the moment my statement is
SELECT * from DEALS WHERE timeofday='post data from form';
Now this works fine, but with the option for 'Anytime' I'd like the query to be able to search for results of all/any of the above.
I was thinking of perhaps doing an IF statement which fires off 2 separate queries, one which says if the $_POST['timeofday'] == 'Anytime' then fire off
SELECT * from DEALS where timeofday='Breakfast'
OR timeofday='Lunch' OR timeofday='Evening';
otherwise just do the normal query, although wondered if it was possible to do this in just one statement.
Kind regards
$query = 'SELECT * from DEALS';
if ($_POST['timeofday'] != 'Anytime') {
$query .= ' WHERE timeofday="' . $_POST['timeofday'] . '"';
}
As DCoder mentioned, this approach is vulnerable to sql injection... You should check/sanitize the input or use prepared statements. In this case where there is a predefined set of values you can:
$knownTimesOfDay = array('Breakfast', 'Lunch', 'Evening', 'Anytime');
if (!in_array($_POST['timeofday'])) {
die('Unsuppotred time of day... Did it really come from the form?');
}
$query = 'SELECT * from DEALS';
if ($_POST['timeofday'] != 'Anytime') {
$query .= ' WHERE timeofday="' . $_POST['timeofday'] . '"';
}
Don't think it can be done in one statement.
You are going to have to use an if statement anyhow.
if these are the only 3 possible values for timeofday,then you can have an if in the php script like this:
if($_POST['timeofday'] != 'Anytime' )
sql .= "where timeofday='".$_POST['timeofday']."'";
This could turn out to be negative depending on the items you have in the table, but you could use:
SELECT * from DEALS where timeofday LIKE '%{$post_data}%'
It would return all the results from timeofday if $post_data was an empty string.

Should I go to the database once and get all the data or twice and get what I need each time

I want some advice on structuring some (basic) php code.
I need to display data from a table in different places. The rows that need to be displayed in each section can be identified by a flag.
I'm not sure if the best way to do this is to go to the database once and seperate the data into 2 variables as I loop through it or if I should go to the database twice, using sql to call only the data I need each time.
For those who want to see it in code:
Method A:
// Create and execute a MySQL query
function tasks_not_done(){
// Open a PDO dtabase connection
$link = new PDO(DB_INFO, DB_USER, DB_PASS);
$sql = " SELECT title, created_date
FROM todos
WHERE list_id = ? AND checked = '0'
ORDER BY created_date DESC";
$stmt = $link->prepare($sql);
$stmt->execute(array($_REQUEST['list_id']));
// loop throught all the rows
while($row = $stmt->fetch()) {
$date = strtotime($row['created_date']);
$date = date('d/m/y' , $date);
echo '<div class="task">' . "\n";
echo '<span class="taskcdtate">' .$date . '</span>'. '<span class="tasktitle"> ' . $row['title'] . ' </span>' . "\n";
echo '</div>';
}
$stmt->closeCursor();
}
Method B
function tasks_all(){
// Open a PDO dtabase connection
$link = new PDO(DB_INFO, DB_USER, DB_PASS);
$sql = " SELECT title, created_date, checked
FROM todos
WHERE list_id = ?
ORDER BY created_date DESC";
$stmt = $link->prepare($sql);
$stmt->execute(array($_REQUEST['list_id']));
// loop throught all the rows
$tasks['not_done'] = "";
$tasks['done'] = "";
while($row = $stmt->fetch("FETCH_ASSOC")) {
$date = strtotime($row['created_date']);
$date = date('d/m/y' , $date);
if($row['checked'] =='0'){
$tasks['not_done'] .= '<div class="task">' . "\n";
$tasks['not_done'] .='<span class="taskcdtate">' .$date . '</span>'. '<span class="tasktitle"> ' . $row['title'] . ' </span>' . "\n";
$tasks['not_done'] .='</div>';
} elseif ($row['checked'] =='1') {
$tasks['done'] .= '<div class="task">' . "\n" .
$tasks['done'] .='<span class="taskcdtate">' .$date . '</span>'. '<span class="tasktitle"> ' . $row['title'] . ' </span>' . "\n";
$tasks['done'] .='</div>';
}
}
$stmt->closeCursor();
return $tasks;
}
thanks
There is no right answer to this kind of question, but I can give you some pointers.
My general rule is: get the data you need when you need it. But there are a lot of things that could affect this.
Will you always use data from both queries ? if yes, you should get all in one query. If Never, meaning they exclude each other, the answer is no.
If you always need query 1, and sometimes query, you have to make a few more considerations. Does query 1 take much more time if you include query 2? How often do you need query 2, almost always or almost never.
What happens if someone else updates data at the same time. Let's say you get both at once, and someone else updates data that affects query 2. This means you're using outdated data. If you fetch the data when you need it, you might get correct updated data.
Method A is my choice.
I think Furnes has some of the best answers so far, but here are a few other things to consider...
From what I can tell... your code isn't that complex in the first place - should you really be worrying about performance with this snippet of code?
Leveraging others' code usually leads to better performance, flexibility and extensibility in the long run. Less of your own code is a good thing. If you choose to delegate the work to the database, there's plenty of optimization that you can literally drop in there, unlike if you rely on your own code. For example, adding indexes to the table you're querying might make more difference than choosing which programming route to take.
If you still want to know the absolutely most efficient way ... why not time/profile the code? See which method is faster using concrete metrics using your own dataset rather than playing the theoretical game.
I can't see the second query here, but you could likely use a JOIN to bring in the additional data.
eg if I have a table of Customers, and a table of Loyalty Cards, but not all customers may have a loyalty card, I could do this:
SELECT c.CustomerID, c.CustomerName, l.LoyaltyCardType, l.LoyaltyCardBalance
FROM Customers c
LEFT JOIN LoyaltyCardInformation l
ON c.CustomerID = l.CustomerID
For MySQL the join syntax is here: http://dev.mysql.com/doc/refman/5.0/en/join.html
Why not do it more elegantly:
$sql = " SELECT title, created_date
FROM todos
WHERE list_id = ? AND checked = ?
ORDER BY created_date DESC";
$stmt = $link->prepare($sql);
$stmt->execute(array($_REQUEST['list_id'], '0'));
# do stuff
# and later...
$stmt->execute(array($_REQUEST['list_id'], '1'));
This avoids code duplication and (depending on the DB backend) should be faster too.
Why not doing this ?
$sql = " SELECT title, created_date
FROM todos
WHERE list_id = ? AND checked = '$filterValue'
ORDER BY created_date DESC";

SQL query building practices

I am building a SQL query that dynamically changes based on passed in $_GET parameters. I simply want to know if putting in a 'dummy' constraint is an 'acceptable' practice, so I do not have to check the SQL string for the existence of 'where' before I add new constraints (each time).
For example, the 'dummy' constraint':
$sql = "select * from users u where u.id != 0";
Now, in each block where I determine if I have to add more constraints, I can just do:
if (!empty($uid))
$sql .= " and (u.id = {$uid})";
Instead of doing:
if (!empty($uid)) {
$sql .= strpos($sql, "where") === false ? " where " : " and ";
$sql .= " (u.id = {$uid})";
}
I've used that convention (although I usually use WHERE 1=1 AND.) Depending on your RDBMS, using a column there could affect performance. For example, if you had an index that would otherwise be a covering index except for that column.
Please make sure that you understand the potential pitfalls of this kind of dynamic SQL, but if it's what you ultimately end up doing, adding that extra bit seems to make sense to me.
Instead of appending to the SQL string for each check, you could collect the conditions:
if ($_GET["uid"]) {
$where[] = array("u.id =", $_GET->sql["uid"]);
if ($_GET["photo"]) {
$where[] = array("u.has_photo =", 1);
And complete the SQL string when you're through:
foreach ($where as $add) {
$sql .= ...;
}
Otherwise, it's an acceptable approach. I wouldn't turn out the big weapons and use a full blown ORM query builder for that.
from the manual
SELECT * FROM table WHERE 1
so yes, you can do that

How do you embedded your sql queries in php scripts (coding-style)?

how do you embed your sql scripts in php? Do you just write them in a string or a heredoc or do you outsource them to a sql file? Are there any best practices when to outsource them ? Is there an elegant way to organize this?
Use a framework with an ORM (Object-Relational Mapping) layer. That way you don't have to put straight SQL anywhere. Embedded SQL sucks for readability, maintenance and everything.
Always remember to escape input. Don't do it manually, use prepared statements. Here is an example method from my reporting class.
public function getTasksReport($rmId, $stage, $mmcName) {
$rmCondition = $rmId ? 'mud.manager_id = :rmId' : 'TRUE';
$stageCondition = $stage ? 't.stage_id = :stageId' : 'TRUE';
$mmcCondition = $mmcName ? 'mmcs.username = :mmcName' : 'TRUE';
$sql = "
SELECT
mmcs.id AS mmc_id,
mmcs.username AS mmcname,
mud.band_name AS mmc_name,
t.id AS task_id,
t.name AS task,
t.stage_id AS stage,
t.role_id,
tl.id AS task_log_id,
mr.role,
u.id AS user_id,
u.username AS username,
COALESCE(cud.full_name, bud.band_name) AS user_name,
DATE_FORMAT(tl.completed_on, '%d-%m-%Y %T') AS completed_on,
tl.url AS url,
mud.manager_id AS rm_id
FROM users AS mmcs
INNER JOIN banduserdetails AS mud ON mud.user_id = mmcs.id
LEFT JOIN tasks AS t ON 1
LEFT JOIN task_log AS tl ON tl.task_id = t.id AND tl.mmc_id = mmcs.id
LEFT JOIN mmc_roles AS mr ON mr.id = t.role_id
LEFT JOIN users AS u ON u.id = tl.user_id
LEFT JOIN communityuserdetails AS cud ON cud.user_id = u.id
LEFT JOIN banduserdetails AS bud ON bud.user_id = u.id
WHERE mmcs.user_type = 'mmc'
AND $rmCondition
AND $stageCondition
AND $mmcCondition
ORDER BY mmcs.id, t.stage_id, t.role_id, t.task_order
";
$pdo = new PDO(.....);
$stmt = $pdo->prepare($sql);
$rmId and $stmt->bindValue('rmId', $rmId); // (1)
$stage and $stmt->bindValue('stageId', $stage); // (2)
$mmcName and $stmt->bindValue('mmcName', $mmcName); // (3)
$stmt->execute();
return $stmt->fetchAll();
}
In lines marked (1), (2), and (3) you will see a way for conditional binding.
For simple queries I use ORM framework to reduce the need for building SQL manually.
It depends on a query size and difficulty.
I personally like heredocs. But I don't use it for a simple queries.
That is not important. The main thing is "Never forget to escape values"
You should always really really ALWAYS use prepare statements with place holders for your variables.
Its slightly more code, but it runs more efficiently on most DBs and protects you against SQL injection attacks.
I prefer as such:
$sql = "SELECT tbl1.col1, tbl1.col2, tbl2.col1, tbl2.col2"
. " FROM Table1 tbl1"
. " INNER JOIN Table2 tbl2 ON tbl1.id = tbl2.other_id"
. " WHERE tbl2.id = ?"
. " ORDER BY tbl2.col1, tbl2.col2"
. " LIMIT 10, 0";
It might take PHP a tiny bit longer to concatenate all the strings but I think it looks a lot nicer and is easier to edit.
Certainly for extremely long and specialized queries it would make sense to read a .sql file or use a stored procedure. Depending on your framework this could be as simple as:
$sql = (string) View::factory('sql/myfile');
(giving you the option to assign variables in the view/template if necessary). Without help from a templating engine or framework, you'd use:
$sql = file_get_contents("myfile.sql");
Hope this helps.
I normally write them as function argument:
db_exec ("SELECT ...");
Except cases when sql gonna be very large, I pass it as variable:
$SQL = "SELECT ...";
$result = db_exec ($SQL);
(I use wrapper-functions or objects for database operations)
$sql = sprintf("SELECT * FROM users WHERE id = %d", mysql_real_escape_string($_GET["id"]));
Safe from MySQL injection
You could use an ORM or an sql string builder, but some complex queries necessitate writing sql. When writing sql, as Michał Słaby illustrates, use query bindings. Query bindings prevent sql injection and maintain readability. As for where to put your queries: use model classes.
Once you get to a certain level, you realise that 99% of the SQL you write could be automated. If you write so much queries that you think of a properties file, you're probably doing something that could be simpler:
Most of the stuff we programmers do is CRUD: Create Read Update Delete
As a tool for myself, I built Pork.dbObject. Object Relation Mapper + Active Record in 2 simple classes (Database Abstraction + dbObject class)
A couple of examples from my site:
Create a weblog:
$weblog = new Weblog(); // create an empty object to work with.
$weblog->Author = 'SchizoDuckie'; // mapped internally to strAuthor.
$weblog->Title = 'A test weblog';
$weblog->Story = 'This is a test weblog!';
$weblog->Posted = date("Y-m-d H:i:s");
$weblog->Save(); // Checks for any changed values and inserts or updates into DB.
echo ($weblog->ID) // outputs: 1
And one reply to it:
$reply = new Reply();
$reply->Author = 'Some random guy';
$reply->Reply = 'w000t';
$reply->Posted = date("Y-m-d H:i:s");
$reply->IP = '127.0.0.1';
$reply->Connect($weblog); // auto-saves $reply and connects it to $weblog->ID
And, fetch and display the weblog + all replies:
$weblog = new Weblog(1); //Fetches the row with primary key 1 from table weblogs and hooks it's values into $weblog;
echo("<h1>{$weblog->Title}</h1>
<h3>Posted by {$weblog->Author} # {$weblog->Posted}</h3>
<div class='weblogpost'>{$weblog->Story}</div>");
// now fetch the connected posts. this is the real magic:
$replies = $weblog->Find("Reply"); // fetches a pre-filled array of Reply objects.
if ($replies != false)
{
foreach($replies as $reply)
{
echo("<div class='weblogreply'><h4>By {$reply->Author} # {$reply->Posted}</h4> {$reply->Reply}</div>");
}
}
The weblog object would look like this:
class Weblog extends dbObject
{
function __construct($ID=false)
{
$this->__setupDatabase('blogs', // database table
array('ID_Blog' => 'ID', // database field => mapped object property
'strPost' => 'Story', // as you can see, database field strPost is mapped to $this->Story
'datPosted' => 'Posted',
'strPoster' => 'Author',
'strTitle' => 'Title',
'ipAddress' => 'IpAddress',
'ID_Blog', // primary table key
$ID); // value of primary key to init with (can be false for new empty object / row)
$this->addRelation('Reaction'); // define a 1:many relation to Reaction
}
}
See, no manual SQL writing :)
Link + more examples: Pork.dbObject
Oh yeah i also created a rudimentary GUI for my scaffolding tool: Pork.Generator
I like this format. It was mentioned in a previous comment, but the alignment seemed off to me.
$query = "SELECT "
. " foo, "
. " bar "
. "FROM "
. " mytable "
. "WHERE "
. " id = $userid";
Easy enough to read and understand. The dots line up with the equals sign keeping everything in a clean line.
I like the idea of keeping your SQL in a separate file too, although I'm not sure how that would work with variables like $userid in my example above.

Categories