I have issues with category and subcategory fields.
shortly, I made category like this: literature, and want to make drop down sub menu like this: poetry, novel, non-fiction.
I receive all the categories on the website, but can't get subcategory field at all.
Here is my code:
$category=htmlspecialchars($_REQUEST['category']);
if(isset($category)){
$avt=mysql_query("select * from category order by id asc");
while($category_id=mysql_fetch_array($avt))
{
?>
<li><a href="#"> <k style="font-size:11px;"> <?
echo $category_id['catname'];
} }
?> </k> </a>
<?
$subcategory=htmlspecialchars($_REQUEST['subcategory']);
if(isset($subcategory)){
$sql = mysql_query("SELECT t1.*,t2.* FROM category as t1, subcategory as t2 WHERE t1.id=t2.'$_REQUEST[subcat_id]'");
while($data = mysql_fetch_array($sql))
{ ?>
<ul style="z-index:101;">
<li> <k> <?php echo $data["subcat_name"]; ?> </k></li>
<? } }
?>
And here is the mysql:
category
id
catname
Subcategory
id
subcat_id
subcat_name
That's all. I would be grateful if some can help me to solve this. (I am beginner obviously)
Thank you
Even though you are a beginner, I would suggest you probably heavily retool this. Start with your database connection. mysql_ functions are deprecated (not recommended for use) in the latest v5 of PHP and removed altogether in PHP v7 because they are security risk and are poorly implemented by most. Use PDO or MySQLi instead. I prefer PDO, so I will demonstrate that:
# Create the connection thusly, fill in your own credentials
$con = new \PDO("mysql:host=localhost;dbname=mydatabase", $username, $password);
Next, you should know the difference between isset and empty. In your case, your isset will throw a warning if $_REQUEST['category'] is not set. When you create your own variable, it's guaranteed to be set when you check it because you manually just created it.
This will throw a warning if $_REQUEST['category'] is not set because you assign it before you check it:
$category = htmlspecialchars($_REQUEST['category']);
This WILL NOT throw a warning because you are checking if $_REQUEST['category'] is set yet. If not, assign $category to false by default:
# I like to use a ternary when there are only two options, but you can use if/else
$category = (isset($_REQUEST['category']))? htmlspecialchars(trim($_REQUEST['category'])) : false;
# This part now checks if the value that you created is NOT EMPTY because you
# have just created it, so checking if it is set is illogical
if(!empty($category)):
# Now we use our connection here to query.
# Here we can use query() because we don't have any variables to add into the query,
# so it's safe to use this short version
$avt = $con->query("select * from category order by id asc");
# Same while loop, just use the PDO version of fetching the results
while($category_id = $avt->fetch(\PDO::FETCH_ASSOC)): ?>
<?php
/**
* I'm not sure why you are using a "k" tag, so just combine with "a" tag
* also, though you can use <? as a php open, it's not recommended
* lastly, you have the close tag for "a" outside the loop, that is bad syntax
* since the open is inside the loop
*/
?>
<li><?php echo $category_id['catname'] ?></li>
<?php endwhile ?>
<?php endif ?>
Now that the top part is finished, you have the same issues (plus a couple more) on this second part of the code:
# It's also worth noting here you have set this variable, but you don't actually use it...?
# Secondly, you are checking for "subcategory" here, but in the code below you are injecting "subcat_id"...should they match??
$subcategory = (isset($_REQUEST['subcategory']))? htmlspecialchars(trim($_REQUEST['subcategory'])) : false;
if(!empty($subcategory)):
# Here is where you need to make a detour with your script. What you are doing is unsafe.
# You can not inject that value right into the sql. You need to "prepare", "bind value", and "execute" it
$subcat_id = $_REQUEST['subcat_id'];
# First prepare using ? as placeholders for the value you want to search for
# The naming convention on the "subcat_id" column I assume is actually the
# the parent category? If so, maybe it should be called "parent_id" or "category_id"??
$sql = $con->prepare("SELECT t1.*, t2.* FROM category as t1, subcategory as t2 WHERE t1.id = ? AND t2.subcat_id = ?");
# Now you want to execute for those two question marks (?)
# There are a few ways to prepare and bind parameters, this way is easy
# and you can visually see what we are trying to accomplish
$sql->execute([$subcat_id, $subcat_id]) ?>
<!-- you probably don't want to be looping this (or it's close tag) -->
<ul style="z-index:101;">
<?php
# Same type of thing as your first block of code
while($data = $sql->fetch(\PDO::FETCH_ASSOC)): ?>
<li> <?php echo $data["subcat_name"] ?> </li>
<?php endwhile ?>
<!-- end list -->
</ul>
<?php endif ?>
The final conclusion here is that you have some work to be done before you get to the main problem which is likely your SQL statement and the value you are querying. I would suggest reading up on any of the concepts mentioned that you are not familiar with.
Related
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.
my xampp localhost was working well till i add this code to my php file
<?php while ($notification) {?>
<li>
<?php
echo $notification['notification'];
?>
</li>
<?php
} ?>
now the page is not loading or partially loading
here $notification is
$notification_sql= "SELECT id FROM notifications WHERE user_id='{$_SESSION['user']}'";
$notification_query = mysqli_query($conn, $notification_sql);
$notification = mysqli_fetch_assoc($notification_query);
Before I begin I want to recommend you something: Avoid the use of the while statetements. Unless they are really needed - like in the exact way they are used in the PHP docs (and even then you can find alternatives) - they should be avoided all the time. I present the motive down under.
That said,... it's not $notification['notification'], but $notification['id'].
After you change it, you still remain with the issue: an infinite loop. Because you are using a while loop without changing the state of the loop condition. E.g_ you are validating the $notification array for beeing existent. Because it exists all the time - it's state never beeing changed in the loop - then the iterations will be infinite in number. In order to avoid this dangerous (!!!) situation, you can use the following codes.
Method 1:
Notice the difference: $notification is valid only for the period of a loop step. After each iteration $notification is newly created. And, when mysqli_fetch_assoc() returns FALSE on the (last + 1)-iteration step, then the $notification receives that value and, therefore, the loop ends.
<?php
$notification_sql = "SELECT id FROM notifications WHERE user_id='{$_SESSION['user']}'";
$notification_query = mysqli_query($conn, $notification_sql);
if ($notification_query) {
while ($notification = mysqli_fetch_assoc($notification_query)) {
?>
<li>
<?php
echo $notification['id'];
?>
</li>
<?php
}
mysqli_free_result($notification_query);
}
?>
Method 2:
Or, if you want to fetch the results in an array and to output its items later, then you can do it like this:
<?php
$notification_sql = "SELECT id FROM notifications WHERE user_id='{$_SESSION['user']}'";
$notification_query = mysqli_query($conn, $notification_sql);
$notifications = array();
if ($notification_query) {
while ($row = mysqli_fetch_assoc($notification_query)) {
$notifications[] = $row['id'];
}
mysqli_free_result($notification_query);
}
// OTHER STUFF AFTER FETCHING...
?>
<?php
// LOOPING AT A LATER TIME.
foreach ($notifications as $notificationId) {
?>
<li>
<?php
echo $notificationId;
?>
</li>
<?php
}
?>
Other recommendations:
Use prepared statements in order to avoid MySQL injection.
Use exception handling in order to catch all errors and handle them correspondingly. Especially when you run database operations.
Use PDO instead of mysqli.
Here I have provided full code examples of prepared statements combined with exception handling (using mysqli library):
Can't insert info in a server, but i can as localhost (See EDIT 2)
Login using MySqli Prepared Statement (See solution 1 & 2)
Good luck.
I'm creating a page for my shop but I was using get_result, and after I finished everything I realised that HostGator couldn't allow me to have mysqlnd running. So I had to convert everything to bind_result instead but I'm in a dead end here probably from being frustrated that I have to change everything...
Anyway my problem is that I call some queries to read tables but the whole code stops after returning 1 result. In this code for example I call for a list of Appointments, although I have like 5 appointments set in the database it only returns the first one. It works as it is supposed to and reads from multiple tables but stops at 1 loop. It wouldn't let me to continue reading the 2nd table if I didn't do a $listappointments_stmt->free_result();
first before the next queries so I think that's my problem but I have no idea how to work arround it as it gives me a boolean error if I don't have it there. Any ideas welcome!
Thank you in advance,
Xenos K.
<?php
$query="SELECT * FROM appointments";
$listappointments_stmt=$mysqli->prepare($query);
$listappointments_stmt->execute();
$listappointments_stmt->bind_result($AppId, $AppDate, $AppTime, $AppType, $AppArtist, $AppTitle, $AppClient, $AppPrice, $AppNotes);
while ($listappointments_stmt->fetch())
{
$theDate=date("d-M-Y", strtotime($AppDate));
echo "<tr><td>".$theDate."</td>";
echo "<td>".$AppTime."</td>";
$listappointments_stmt->free_result();
$tempappointmentType=$AppType;
$query2="SELECT * FROM appointmenttypes WHERE ID=?";
$listappointmentsTypes_stmt=$mysqli->prepare($query2);
$listappointmentsTypes_stmt->bind_param("s", $tempappointmentType);
$listappointmentsTypes_stmt->execute();
$listappointmentsTypes_stmt->bind_result($AppTypeId, $AppTypeName, $AppTypeColor);
while ($listappointmentsTypes_stmt->fetch())
{
echo "<td><span class=\"label\" style=\"background-color:".$AppTypeColor."\">".$AppTypeName."</span></td>";
}
$listappointmentsTypes_stmt->free_result();
$listappointmentsTypes_stmt->close();
$tempappointmentArtist=$AppArtist;
$query3="SELECT * FROM staff WHERE ID=?";
$listappointmentsArtist_stmt=$mysqli->prepare($query3);
$listappointmentsArtist_stmt->bind_param("s", $tempappointmentArtist);
$listappointmentsArtist_stmt->execute();
$listappointmentsArtist_stmt->bind_result($ArtId, $ArtName, $ArtNickName, $ArtSurname, $ArtPhone, $ArtBirthDate, $ArtIdentificationNumber, $ArtStreetName, $ArtStreetNumber, $ArtPostalCode, $ArtCity, $ArtCountry, $ArtPosition, $ArtEmail, $ArtFacebook, $ArtInstagram);
while ($listappointmentsArtist_stmt->fetch())
{
echo "<td>".$ArtName." ".$ArtNickName." ".$ArtSurname."</td>";
}
$listappointmentsArtist_stmt->free_result();
$listappointmentsArtist_stmt->close();
echo "<td>".$AppTitle."</td>";
$tempappointmentClient=$AppClient;
$query4="SELECT * FROM clients WHERE ID=?";
$listappointmentsClient_stmt=$mysqli->prepare($query4);
$listappointmentsClient_stmt->bind_param("s", $tempappointmentClient);
$listappointmentsClient_stmt->execute();
$listappointmentsClient_stmt->bind_result($CliId, $CliName, $CliSurname, $CliPhone, $CliBirthDate, $CliIdentificationNumber, $CliStreetName, $CliStreetNumber, $CliPostalCode, $CliCity, $CliCountry, $CliFathersFullName, $CliMothersFullName, $CliEmail, $CliFacebook, $CliInstagram, $CliNotes);
while ($listappointmentsClient_stmt->fetch())
{
echo "<td>".$CliName." ".$CliSurname."</td>";
echo "<td>".$CliPhone."</td>";
}
$listappointmentsClient_stmt->free_result();
$listappointmentsClient_stmt->close();
echo "<td>".$AppPrice."</td>";
echo "<td><i class=\"text-green fa fa-eye\"></i></td>";
echo "<td><i class=\"text-blue fa fa-edit\"></i></td>";
echo "<td><i class=\"text-red fa fa-trash-o\"></i></td></tr>";
}
$listappointments_stmt->close();
?>
You'll be wise to learn to use JOIN statements in SQL. This will allow you to use just one SQL query to fetch all the results you need.
In the meantime, if you are nesting some SQL queries inside others, the outside query (in your case SELECT * FROM appointments) needs a separate database connection (in your case $mysqli) from the rest of the queries. Issuing a new query from the connection resets the rest of the queries.
Pro tip: Avoid using SELECT * in production software. Instead give a list of columns you need. Your software will be more robust and easier to understand if you do that.
I am using MySQLi multi_query to work with several select statemets at a time.
What i would like to know is how to handle results, so i will be able to use them later in code.
Example:
<?php
//connection stuff
$query = "SELECT name, surname FROM database1;";
$query.= "SELECT car, year, type FROM database2 WHERE carID='1';";
$query.= "SELECT product, price FROM database3;";
if ($mysqli->multi_query($query)) {
if($result = $mysqli->store_result()) {
while($row = $result->fetch_row()) {
--> what to do here?
}
}
}
?>
<html>
<div id='persona'>
<?php
foreach() {
--> print name + surname
}
?>
</div>
<div id='cars'>
<?php
foreach() {
--> print car + year + type
}
?>
</div>
<div id='product'>
<?php
foreach() {
--> print product + price
}
?>
</div>
</html>
One more thing, prepared statements are not possible when using multiple_query, right?
There really is no benefit in putting unrelated queries together in one multi query call. In fact, the risk of getting hit by a SQL injection is way bigger! The regular query function does only allow one query per call, so it is impossible to inject something into a SELECT statement, ending it prematurely and then add a DELETE.
With multi_query, this is possible.
Additionally, you have to fetch and end each query, and then it's gone. You you cannot change between the query results at will, they have to be fetched in exactly the order they were issued.
The better way is to just execute independent simple queries. This would allow you to use prepared statements as well, and as long as you are not getting HUGE amounts of data back, it will probably use the same amount of memory and not annoy anyone.
I have a page that is querying a database quite a few times using php with that's being repeated; the query blocks are interspersed with html in between as well. An example is
<?php
--code here--
SELECT DISTINCT `Retailer`
FROM `product`
WHERE `Product` = 'iPad 2'
--continue code here--
?>
html content here
<?php
--code here--
SELECT DISTINCT `Brand`
FROM `product`
WHERE `Product` = 'iPad 2'
--continue code here--
?>
This is repeated a few times. This page that the queries sit on will need to duplicated for other pages but the "Product" line have to change (for example, Product = 'iPhone'). Currently, each of the queries is located within separate php code blocks so I have to go to each place where it is referenced to change it. Is it possible to have one location at the top of the document that I can change? If so, how do I do this?
I personally like using the $_GET variable for things like this, using mod_rewrite to generate necessary URLs that don't include the variables. I assume that some of your html changes along with the WHERE line of your query, too. You could try something like this:
Links to product pages
<ul>
<li>iPad 2</li>
<li>iPhone 4S</li>
</ul>
The products/index.php document
<?php
$product = $_GET['product'];
//various code
$retailer_result = mysql_query("SELECT DISTINCT Retailer FROM product WHERE Product = '$product'");
//more code
//define and require the html document
$product_page_dir = "products/pages/";
$product_page_path = $product_page_dir . $product;
require $product_page_path;
//more various code
$brand_result = mysql_query("SELECT DISTINCT Brand FROM product WHERE Product = '$product'");
//the rest of the code
This is the simplest way of doing it using this method. Don't forget to establish the connection MySQL and select the database before any queries. Also keep in mind that you should also probably include error handling. Note: the code above is untested.
You probably mean to write something like a function that you can reuse:
function get_product($column, $name) {
return db("SELECT DISTINCT `$column` FROM `product` WHERE `Product` = ?", $name);
}
Then just set a variable $product_name atop your page, and reuse that for issueing the queries. (If that's what you meant.)
$product_name = "iPad 2";
...
get_product("Retailer", $product_name);
...
get_product("Brand", $product_name);
...
get_product("Price", $product_name);