SQL not working correctly with user-made variable - php

I'm having trouble with my MySQL results, I have a table named "posts" and one column is named "category" which is an integer value. I created a variable to get the category number from the browser depending on which category link a user clicks on.
If the category number is "1" it should display a test post(which is does).
But if the category number is anything other than "1" which is the category id, it still shows the same test post when it should say "No results found" since it is querying for a different category id number.
I'm guessing it has something to do with the SQL syntax cause I've done added single-quotes around the variable name, and it error'd out so I removed them. I'm only posting the necessary code below cause I know it has something to do with that variable in the SQL:
// Variable to hold number
$category = is_numeric($_GET["c"]);
// Query
$query = "SELECT * FROM posts WHERE category = $category";
NOTE: Now i'm having a different issue. I need to make it so when there are results the while statement goes through and displays them, but if there are no results, display another message. The issue is it wont display the no results message when there are no results. Here is my code:
while($results = mysqli_fetch_assoc($query))
{
echo '$results["title"] <br>';
}
if(count($results) == 0 || count($results) == null) {echo 'No results';}
I've tried placing the if statement in the while and outside like so, but neither way works. I have to have the while statement cause I know i'll have more than one result so I can't use an if statement. The while statement needs an else!

You're turning the category into a boolean value.
You actually want this:
$category = intval($_GET['c']);

is_numeric returns true/false, so your query is "SELECT * FROM posts WHERE category = true"
Try this:
if(is_numeric($_GET["c"])) {
$category = $_GET["c"];
} else {
// exit the script or set a default value
}
// ...

Your variable inside your query need additional ' apostrophes like this
$query = "SELECT * FROM posts WHERE category = '$category'";
One more thing, if you are trying to specifically detect numbers in PHP use the ctype
function
if (ctype_alpha($id){
//do something
}

cast it to int!
$category = (int) $_GET["c"];
and then
if (!empty($category))
{
// do your stuffff
}

Related

MySQL/PHp Filter Results List Error

I have a legacy PHP script which creates a list of resources from information stored in a MySQL database. Users can search the list or filter by the first letter in the title (this is stored as a column in the database). You can see it in action here: http://lib.skidmore.edu/library/index.php/researchdatabases). The script works fine except for one resource, FT.com, which appears incorrectly when users filter by letter. Regardless of the letter selected, its entry will be either at the top or the bottom. Note that in the unfiltered view FT.com is in proper alphabetical order. My first thought was to look at the database entry, but everything looks fine.
My hypothesis is a variable is not being set correctly. The way the script works is the top half of it contains a web form. The PHP below then picks up the input and assigns it to the variable $searchletter.
A combination of while loops and mysqli queries then retrieves and displays the results. Interestingly when the $searchletter = !empty line is commented out, the entire list disappears for the unfiltered view except for the FT.com entry (see this test script for an example: http://lib.skidmore.edu/library/search_dbs2.php). Otherwise I can see anything in neither the script nor the database which might be causing the observed behavior. Is my suspicion correct?
Here is the code. I've included everything except the connection information so you can see how it all works.
$search=(isset($_GET['search']) ? $_GET['search'] : null);
$search = !empty($_GET['search']) ? $_GET['search'] : 'default';
$search= addslashes($search);
$searchletter=(isset($_GET['searchletter']) ? $_GET['searchletter'] : null);
$searchletter = !empty($_GET['searchletter']) ? $_GET['searchletter'] : 'default';
var_dump ($_GET['searchletter']);
$con=mysqli_connect(DB_HOST,WEBMISC_USER,WEBMISC_PASS,DB_NAME);
if (mysqli_connect_errno())
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
if ($search == "default" && $searchletter == "default"){
$result = mysqli_query($con,"SELECT title,summary,url,coverage,format FROM dbs");
//This while loop creates the inital A to Z list.
while($row = mysqli_fetch_array($result))
{
$url=$row['url'];
$title=$row['title'];
$summary=$row['summary'];
$coverage=$row['coverage'];
$format=$row['format'];
echo <<<HTML
<p><h6>$title</h6>
<br />$summary</p>
HTML;
}
}
else {
$result = mysqli_query($con,"SELECT title,summary,url,coverage,format,fletter FROM dbs where title like '%$search%' or summary like '%$search%' or fletter = TRIM('$searchletter')");
//This block creates the filtered and searched version of the list.
while($row = mysqli_fetch_array($result))
{
$url=$row['url'];
$title=$row['title'];
$summary=$row['summary'];
$coverage=$row['coverage'];
$format=$row['format'];
echo <<<HTML
<p><h6>$title</h6>
<br />$summary</p>
HTML;
}
mysqli_close($con);
the first serious problem with this script is that it seems to be prone to MySQL Injection, the most serious problem of them all. (but I may be wrong). Please consider switching this code to PDO and its prepared statements and bindParam method.
the second is that, in the FORM you either support search OR letter (but not both)
BUT you use both in mysql query.
you should split the result fetching from
$result = mysqli_query($con,"SELECT
title,summary,url,coverage,format,fletter
FROM dbs
where title like
'%$search%' or summary like '%$search%' or fletter = '$searchletter'");
into if/else statement:
if(!empty($search)){
$result = mysqli_query($con,"SELECT
title,summary,url,coverage,format,fletter
FROM dbs
where title like
'%$search%' or summary like '%$search%'");
} elseif(!empty($searchletter)){
$result = mysqli_query($con,"SELECT
title,summary,url,coverage,format,fletter
FROM dbs
where fletter = '$searchletter'");
}
this will not fire BOTH cases on the search and should return more reliable result based on your selection.
EDIT: after you added more code, it's clear that every "unset by user" field has value of "default". which means:
whatever letter you chose, the "seachphrase" will be set to "default" and "default" appears to be a part of FT.com summary field (you can see this word in search results). Again: splitting the query into two cases will solve this, so "default" word is never used in the search query.

Information regarding SQL queries, stored with php

So let me explain my problem, lets assume that I run query like so:
$myquery = sql_query("SELECT name FROM table WHERE name='example' LIMIT 0,1");
Now.. I want to store the retrieved name into a variable so I would do something like this:
while ($myrow = sql_fetch_assoc($myquery)) {
transfer_row($myrow);
print"Name: $row_name";
}
$stored_name = $row_name;
NOTE: transfer_row() is just a function I wrote that takes $myrow['name'] and stores it in $row_name, for easier reference
Now, all is fine at this stage, here is where it gets interesting. Note that at this stage I still have a name assigned to $row_name. Further down the page I run another query to retrieve some other information from the table, and one of the things I need to retrieve is a list of names again, so I would simply run this query:
$myquery = sql_query("SELECT name, year FROM table WHERE DESC LIMIT 0,10");
while ($myrow = sql_fetch_assoc($myquery)) {
transfer_row($myrow);
$year = $row_year;
$link = "/$year";
print "<li style=\"margin-bottom: 6px;\">$row_name\n";
}
Now, I want to write an if statement that executes something if the $row_name from this query matches the $row_name from the old query, this is why we stored the first $row_name inside the variable.
if ($row_name == $stored_name){
// execute code
}
However as most of you know, this WONT work, the reason is, it simply takes $stored_name again and puts the new $row_name into $stored_name, so therefore the value of the first $row_name is lost, now it is crucial for my application that I access the first $row_name and compare it AFTER the second query has been run, what can I do here people? if nothing can be done what is an alternative to achieving something like this.
Thanks.
EDIT, MY transfer_row() function:
function transfer_row($myrow) {
global $GLOBALS;
if(is_array($myrow)) {
foreach ($myrow as $key=>$value) {
$key=str_replace(":","",$key);
$GLOBALS["row_$key"] = $value;
}
}
}
Without you posting the code for the function transfer_row, we won't be able to give you an answer that exactly matches what you request, but I can give you an answer that will solve the problem at hand.
When matching to check if the names are the same, you can modify the if statement to the following.
if ($row_name == $myrow['name']){
// execute code
}
What I suggest you do though, but since I don't have the code to the transfer_row function, is to pass a second variable to that function. The second variable will be a prefix for the variable name, so you can have unique values stored and saved.
Refrain from using the transfor_row function in the second call so your comparison becomes:
if ($myrow['name'] == $row_name)
If you need to use this function, you could do an assignment before the second database call:
$stored_name = $row_name;
...
transfer_row($myrow);
In your first query you are selecting the name field WHERE name='example' , Why are you quering then? You already have what you want.
Your are querying like:
Hey? roll no 21 what is your roll no?
So perform the second query only and use the if condition as :
if ($row_name == 'example'){
// execute code
}
Does it make sense?
Update
//How about using prefix while storing the values in `$GLOBAL` ??
transfer_row($myrow, 'old_'); //for the first query
transfer_row($myrow, 'new_'); //for the second query
function transfer_row($myrow, $prefix) {
global $GLOBALS;
if(is_array($myrow)) {
foreach ($myrow as $key=>$value) {
$key=str_replace(":","",$key);
$GLOBALS["$prefix"."row_$key"] = $value;
}
}
}
//Now compare as
if ($new_row_name == $old_row_name){
// execute code
}
//You'll not need `$stored_name = $row_name;` any more

PHP check if variable exists in all rows returned

i want to do a check if a user id exists in all of the table rows i search for.
edit sorry i was missleading i think.
I want to check if the user has read all of the articles in a category, i have a forum front end displaying the categories and within the categories are the articles.
On the categories screen i want to display an image ALL ARTICLES READ or NOT ALL ARTICLES READ, so some how i need to loop through all of the articles per category which is what the example query below is doing and check if user id exists in ALL returned rows if yes then then all articles have been read if there are some rows missing the users id then some articles have not been read
This is my sql query
$colname_readposts = "-1";
if (isset($_GET['Thread_Category_Article_id'])) {
$colname_readposts = $_GET['Thread_Category_Article_id'];
}
mysql_select_db($database_test, $test);
$query_readposts = sprintf("SELECT Thread_Article_User_Read FROM Thread_Articles WHERE Thread_Category_Article_id = %s", GetSQLValueString($colname_readposts, "int"));
$readposts = mysql_query($query_readposts, $cutthroats) or die(mysql_error());
$row_readposts = mysql_fetch_assoc($readposts);
$totalRows_readposts = mysql_num_rows($readposts);
How can i check if all of the rows returned contain the users id?
The idea is to check to see if user has read all the articles if yes show READ if no show UNREAD.
The results per row are like so 0,15,20,37 these are id's entered when a user views a post.
i have managed to get this check for a single article to show if the user has read a specific article but unsure how i would check multiple:
here is my single article check:
<?php
$userid = $_SESSION['loggedin_id'];
$userreadlist = $row_readposts['Thread_Article_User_Read'];
$myarray = (explode(',',$userreadlist));
if (in_array($userid,$myarray )){
?>
html image READ
<?php } else { ?>
html image UNREAD
<?php } ?>
Any help would be appreciated.
Carl
First up, forget the mysql_* functions; ext/mysql is a deprecated API as of PHP 5.5 - so it's a really good idea to use mysqli or PDO.
From what I gather you're actually trying to see if any of those results contain a specific user's id? If so, do this in the SQL query:
SELECT Thread_Article_User_Read FROM Thread_Articles WHERE
Thread_Category_Article_id = %s AND UserID = %s
And supply this the User's ID as a second argument. (Syntax may not be 100% correct, but it should prove a point)
If you mean you want to check there there is any user's ID - then once again; do this in SQL:
SELECT Thread_Article_User_Read FROM Thread_Articles WHERE
Thread_Category_Article_id = %s AND UserID IS NOT NULL
This will ensure there is a valid value for 'UserID'.
Naturally replace 'UserID' with your column name if you base your solution on one of these examples.
However, if you're dumping out ALL the results from a table - and you need to see if your user's ID is present in a certain column (like you do!); then you can actually just adapt the logic that you're using on your single article page. Which should give you something like this...
$userid = $_SESSION['loggedin_id'];
$colname_readposts = "-1";
if (isset($_GET['Thread_Category_Article_id'])) {
$colname_readposts = $_GET['Thread_Category_Article_id'];
}
/* connect to db and run query; CHANGE ME TO SOMETHING NOT DEPRECATED */
mysql_select_db($database_test, $test);
$query_readposts =
sprintf("SELECT Thread_Article_User_Read FROM Thread_Articles WHERE
Thread_Category_Article_id = %s", GetSQLValueString($colname_readposts, "int"));
$readposts = mysql_query($query_readposts, $cutthroats) or die(mysql_error());
/* loop through all returned items */
while($row = mysql_fetch_assoc($readposts)) {
/* repeat the check you used on an individual
row on the single article page. i.e: */
$userreadlist = $row['Thread_Article_User_Read'];
$myarray = (explode(',',$userreadlist));
if (in_array($userid,$myarray )){
/* user has read */
} else {
/* user hasn't read */
}
}
If that code you worked for a single page then it should work in the above; as for every iteration of the loop you're working on a single row - just as you were on the single page. If the data is coming from the same table then the column names etc match up and it will work.
Or, if you just want to know if there are any unread posts at all, replace the loop with this one...
/* loop through all returned items */
$read = true;
while($row = mysql_fetch_assoc($readposts)) {
/* repeat the check you used on an individual
row on the single article page. i.e: */
$userreadlist = $row['Thread_Article_User_Read'];
$myarray = (explode(',',$userreadlist));
if (! in_array($userid,$myarray )){
$read = false;
break;
}
}
if( $read ){
/* all pages are read */
} else {
/* there are unread pages */
}

Performing a MYSQL query based off of $_GET results

When a user clicks an item on my items page, it takes them to blank page template using $_GET to pass the item brand and model through.
I'd like to perform another MYSQL query when that user clicks through to populate the blank page with the product details from my database. I'd like to retrieve the single row using the model number (unique ID) to populate the page with the information. I've tried a couple of things but am having a little difficulty.
On my blank item page, I have
$brand = $_GET['Brand'];
$modelnumber = $_GET['ModelNumber'];
$query = mysql_query("SELECT * FROM items WHERE `Model Number` = '$modelnumber'");
$results = mysql_fetch_row($query);
echo $results;
I think having ''s around Model Number is causing troubles, but without them, I get a Warning: mysql_fetch_row() expects parameter 1 to be resource, boolean given error.
My database columns looks like
Brand | Model Number | Price | Description | Image
A few other things I have tried include
$query = mysql_query("SELECT * FROM item WHERE Model Number = $_GET['ModelNumber']");
Which gave me a syntax error. I've also tried concatenating the $_GET which gives me a mysql_fetch_row() expects parameter 1 to be resource, boolean given error
Which leads me to believe that I'm also going about displaying the results incorrectly. I'm not sure if I need to put it in a where loop like I have with my previous page which displays all items in the database because this is just displaying one.
It seems that your "result" is pulling in too much information for a single variable.
Also, I don't think your table should have column names with spaces, I would suggest filling them all with dashes or underscores.
Here's my suggestion:
$qry = mysql_query("SELECT * FROM items WHERE Model_Number = '$modelnumber'"); //REMEMBER TO MAKE THE CHANGE "Model Number" -> "Model_Number"
while($row = mysql_fetch_array($qry)){
$brand = $row['Brand'];
$modelnumber = $row['Model_Number'];
$price = $row['Price'];
$description = $row['Description'];
$image = $row['Image'];
}
This will populate all of these variables with whatever you have in your tables.
First, notice the first comment on your question. You definitely want to add some sort of sanitation, mysql_real_escape_string at the very least, although PDO or Mysqli would be preferred.
Second, before getting a real answer to your question, let's get some more information about your error.
Try the following:
$brand = mysql_real_escape_string($_GET['Brand']);
$modelnumber = mysql_real_escape_string($_GET['ModelNumber']);
$query = mysql_query("SELECT * FROM items WHERE `Model Number` = '$modelnumber'")OR die(mysql_error());
$results = mysql_fetch_row($query);
var_dump($results);
mysql_error tell us what is going on behind the scenes.
If you are using mysql_fetch_row it will only returns a numerical array of strings that corresponds to the fetched row, or FALSE if there are no more rows http://php.net/mysql_fetch_row
If you need to retrieve the data inside that row. You need to use mysql_fetch_array()
also try using mysql_error();
$results = mysql_fetch_row($query) or die(mysql_error());
you will see the error output produce by your code

what is the official value of an empty sql result(from a loop)

What I mean is, for example, if I search for something on an SQL table, and it returns 0 / nothing, is that null or empty or does it result in an empty ""?
I'm getting back into php and trying to loop through a db like so:
Pseudo code:
while($row = mysqli_fetch_array($var here that has the query to the db and connection)){
echo $row[//something pulled from table to be read back]
}
But let's say that the search query didn't return any results or that $row doesn't equal to anything because for whatever reason, the value searched for in the db doesn't exist,
How then can I check for the empty-ness of row?
if the searched for item doesn't exist in the db, then $rows value becomes what exactly? null/empty/or empty string or something else?
depending on the value of row, do I test for [isset / !isset] or [empty / !empty] ? Or is the only way to test for empty $row to do a (pseudo) $x =mysqli_num_rows(var here) / if ($x == 0 ) //do something?
If mysqli_fetch_array did not return anything, then the return value is NULL
The line while($row = mysqli_fetch_array is supposed to return the next available record in the record set, so if the query did not give any matching results, then the line echo $row['something'] does not get executed at all.
If there are multiple fields you are fetching, say field1, field2 and supposing field2 doesn't have a value, then what is returned for that field is what the default value for that field will be in MySQL (or whichever DB you are using). However the point to note is that $row will still have two keys defined correctly as $row['field1'] and $row['field2']
If you want to check if $row['field2'] does have any value you can check it using empty($row['field2']).
"", 0, NULL, FALSE, array() are all considered empty() so you should be able to safely determine if the field has any valid value in it using this function. However, if say 0 could be a valid value (for e.g. you are querying no_of_days a person was absent last month and some of them have full attendance), you will need to explicitly check the value in the field and cannot depend on empty().
You can check whether there is result using mysql_num_rows. If there is items exist in that row, the row should have show one or more or TRUE depending on the item you searched, if nothing exist in database when you executed the query means the mysql_now_rows will show you 0/NULL.
You can do like
$query = mysql_query("YOUR QUERY HERE");
$numrow = mysql_num_rows($query);
if ($numrow == 0)
{
ECHO "No result found.";
}
When there's nothing, $row == false
That's the correct test on the while loop!
You can use mysqli_num_rows to fetch the number of results found by a query.
$query = 'SELECT `blah`';
$result = mysqli_query($query);
if(mysqli_num_rows($result) > 0) {
// do stuff here if any rows are found
} else {
// do stuff here if NO rows are found
}

Categories