I have a table that stores images of three categories: cars, bikes, buses. These images appear on two pages. On the first page, you should see an image of each category, defined so random. On the second page, you should see the remaining pictures. How can I do this using php?
I would prefer to do this in MySQL, you can set the order to:
ORDER BY MD5(ImageNo+UserRandomNumber)
SQL FIddle
You can generate a single random number per user, store this in the session then apply this to the ordering and as long as the number supplied stays the same, the order will remain the same too.
You can indeed use a session to store which images were shown on the first page, and then leave them out on the second page. Without knowing your exact table structure, something like this should work:
<?php
// page 1
session_start();
function get_random_image_id($category)
{
// SELECT id FROM images WHERE category = $category ORDER BY RAND() LIMIT 1
}
function show_image($id)
{
// SELECT * FROM images WHERE id = $id
// echo <img ...>
}
$_SESSION['image_ids'] = array(
get_random_image_id("cars"),
get_random_image_id("bikes"),
get_random_image_id("buses"),
);
foreach($_SESSION['image_ids'] as $image_id)
{
show_image($id);
}
?>
<?php
// page 2
session_start();
function show_images($exclude_ids)
{
$ids = implode(",", $exclude_ids);
// SELECT * FROM images WHERE id NOT IN ($ids)
}
$exclude = array();
if(isset($_SESSION['image_ids'])) // has the user visited page 1?
{
$exclude = $_SESSION['image_ids'];
}
show_images($exclude);
?>
Related
I am creating my own blog from scratch with a homepage that loads the latest posts in order of time published. I call the posts using a front controller and store the data on a MySQL database. The website itself is great and the posts all load perfectly with no issue. The issue is getting the homepage to work.
I created a few PHP functions for the homepage. They generally order the posts (database rows) by ID in descending order, since it's an autoincrement field, and call their data. And then to show the latest post as a sort of 'featured post' right at the top, by fetching the data from the very top row in the database, which is the latest post.
And that works fine - when I echo the result it shows the latest post just as I want it.
Below that I want two boxes, side by side, for the two posts before the first one. So I made this function to call them:
function fetch_rest_posts_1($conn) {
$stuff = $conn->query("SELECT * FROM table WHERE is_post = 1 ORDER BY id DESC LIMIT 1,2");
while ($row = $stuff->fetch_array()) {
$i=1;
return '<div id="post_'.$i.'" style="width:308px;height:215px;padding:5px">
<h2>'.$row['title'].'</h2>
<p>'.date('d/m/Y',strtotime($row['published_date'])).' by '.$row['author'].' | </p>
<p>'.$row['meta_description'].'</p>
</div>';
$i++;
} // style="white-space:nowrap;width:100%;overflow:hidden;text-overflow:ellipsis"
}
And it actually does work great when I echo the result, shows everything I want, but it only shows one div, not two. When I take the SQL query and directly enter it into phpMyAdmin, it gives me two rows. Have I done something wrong?
(I put the auto-increasing $i in there so that I could isolate each box and alter the style later.)
Your problem is caused by the return statement in the loop. You should add $return = '' at the top of your function, replace return by $result .=, and return $result at the end of your function.
In addition, the loop counter $i is reset in every iteration. Move the initial assignment out of the loop.
EDIT: The .= is intentional to append to $result instead of replacing it with another value constructed from the next dataset.
initiate $i outside the loop and use echo() instead of return()
return() breaks the loop
or use
$result .= '<div id="post_'.$i.'" style="width:308px;height:215px;padding:5px">
<h2>'.$row['title'].'</h2>
<p>'.date('d/m/Y',strtotime($row['published_date'])).' by '.$row['author'].' | </p>
<p>'.$row['meta_description'].'</p>
</div>';
and return $result; after the loop
That's because return will stop execution of the function try this approach:
function fetch_rest_posts_1($conn) {
$stuff = $conn->query("SELECT * FROM table WHERE is_post = 1 ORDER BY id DESC LIMIT 1,2");
$post = array();
while ($row = $stuff->fetch_array()) {
$post[] = $row;
}
return $post;
}
So the function purpose is to just get the data, so you can later print it:
$row = fetch_rest_posts_1($conn);
for($i = 0; count(row); $i++){
echo '<div id="post_'.$i.'" style="width:308px;height:215px;padding:5px">
<h2>'.$row[$i]['title'].'</h2>
<p>'.date('d/m/Y',strtotime($row['published_date'])).' by '.$row[$i]['author'].' | </p>
<p>'.$row[$i]['meta_description'].'</p>
</div>';
}
I'm trying incorporate a "News Feed" into my site, pulling information from two different tables (Using two seperate queries). One feed pulls current stories "$newsfeed" and the other pulls history stories "$historyfeed". Both tables need to remain seperate. I'm attempting to place these queries in a random order for a set number or rows. For example, I want 5 stories listed, with history and news choosen randomly.
The order might be: History, News, History, History, History
the next visit might produce: News, News, New, History, News
This part seems to work fine...
However, I've been unable to move to the next row in the query. So five of the exact same news stories are produced, instead of moving to the next row of the query. See the example code below:
//DB connection established earlier
$newsfeed = mysql_query("SELECT * FROM newsfeed WHERE story_type='business'"); //News Story Query
$row_newsfeed = mysql_fetch_assoc($newsfeed);
$historyfeed = mysql_query("SELECT * FROM newsfeed WHERE story_type='business'"); //History Story Query
$row_historyfeed = mysql_fetch_assoc($historyfeed);
$storycount = 0;
while ($storycount < 5) {
$storytype = rand(1,2); //randomly select next story type
switch ($storytype){
case: "1" //if next story is a new story
storybubble($row_newsfeed); //function to echo newsfeed content
$storycount++;
break;
case: "2" //if next story is a history story
storybubble($row_historyfeed); //function to echo historyfeed content
$storycount++;
break;
default:
echo "Error";
} //switch statement
} //story count while statement
You create the variables at the top, and load stories into $historyfeed and $newsfeed; but you keep using the same variables in your loop. This should work a little better:
case: "1" //if next story is a new story
$row_newsfeed = mysql_fetch_assoc($newsfeed);
storybubble($row_newsfeed); //function to echo newsfeed content
$storycount++;
break;
case: "2" //if next story is a history story
$row_historyfeed = mysql_fetch_assoc($historyfeed);
storybubble($row_historyfeed); //function to echo historyfeed content
$storycount++;
It's populating the variables when they're needed, instead of at the start of the code.
mysql_fetch_assoc() returns one row of the result.
If you want to return the next row you need to call mysql_fetch_assoc() again.
So you could change your calls to storybubble to:
storybubble(mysql_fetch_assoc($row_newsfeed));
However, you'll probably be better off to build an array of the rows and then pull from that.
$newsfeed = array();
$historyfeed = array();
while($row = mysql_fetch_assoc($newsfeed)) {
$newsfeed[] = $row;
}
while($row = mysql_fetch_assoc($historyfeed)) {
$historyfeed[] = $row;
}
...
switch($storytype) {
case 1:
storybubble(array_shift($newsfeed));
break;
}
...
I need to get a random number between, lets say 1-200, but at the same time I need to prevent selecting a random number that has already been used for a particular REMOTE_ADDR (as stored in a table).
This is what I have so far (I have tried several different approaches):
$ip = $_SERVER['REMOTE_ADDR'];
$query7 = "
SELECT *
FROM IP
WHERE IP = '$ip'
";
$result7 = mysql_query($query7) or die(mysql_error());
$rows7 = mysql_num_rows($result7);
while ($row7 = mysql_fetch_array($result7)){
$id = $row7['ID'];
}
I'm using the random number to pick an image to display, but my users are complaining that the images selected for them is not random enough; ie, the same picture is getting "randomly" selected too often, sometimes showing the same image over and over.
It does not have to be in PHP, if there is another option.
Something like that
// all ids from 1 to 100
$all = array_fill(1, 200, 0);
// remove used
foreach ($used as $i) {
unset($all[$i]);
}
// get survived keys
$keys = array_keys($all);
// get random position, note that the array with keys is 0 based
$j = rand(0, count($all) - 1);
return $keys[$j];
Run your select and instead of using *, only select the id column. Then use:
while($row7[] = mysql_fetch_array($query7));
do{
$rand = rand(0,200);
}while(in_array($rand,$row7));
You can do it all in mysql. Have one table that has your list of images, and another table that has the list of IP addresses and the images that have already been shown to that IP. Then you select and join the tables and order the result randomly.
SELECT image_id FROM images
LEFT JOIN shown_images ON images.image_id=shown_images.image_id AND ip_addr=[#.#.#.#]
WHERE shown_images.image_id IS NULL
ORDER BY RAND() LIMIT 1;
After you show an image to an IP, just insert a record into the shown_images table with the IP and the image ID. That will work right up until that have seen all the images. Then you can delete the records and start over.
This answer assumes that you have 200 items, and collect the items which you do not want to show. Alternatively, you can query only id's of available items and choose from these, you would need to create a table with available items for that.
Create a map which maps consecutive numbers to (non-consecutive) available numbers. Suppose the numbers 1 and 3 are in use, you can map to 2 and 4 (and so on).
Actually, it is possible to use a simple array (not-associative) for this. You can do something like this:
$reserved = array(1, 3); // fill $reserved using your code
$available = array();
for ($i = 1; $i <= 200; $i++) {
if (!in_array($i, $reserved)) {
$available[] = $i;
}
}
if (count($available) > 0) {
$random_index = rand(0, count($available) - 1);
$r = $available[$random_index];
} else {
// Nothing available!
}
There will be nothing to choose when you run out of pictures that have not been displayed yet. In this case, count($available) will be zero. One way to solve this would be to clear your list of displayed images for the current IP and choose again; see also other answers for this.
I have products stored in a database. These items have ID, NAME, QUANTITY, and STOCK_NUMBER fields. I want to make an href for all of the data in the database:
$Result=mysql_query("SELECT * FROM Products");
while($row=mysql_fetch_array($Result)){
href .....
}
I want the result like this
item_id=1&name_1_tv&quantity_1=2&stock_number_1=1411
&item_id=2&name_2_mobile&quantity_2=5&stock_number_2=5894
&item_id=3&name_3_radio&quantity_3=2&stock_number_3=18541
&item_id=4&name_4_tv&quantity_4=2&stock_number_4=1025
&item_id=5&name_5_computer&quantity_5=1&stock_number_5=1455
&item_id=6&name_6_cd&quantity_6=2&stock_number_6=5888
all these under the link
Use http_build_query().
while($row=mysql_fetch_assoc($Result)) // note the change to assoc
{
$query = http_build_query($row);
echo "&$query<br>";
}
Note that GET requests have very low maximum length limits. IE chokes on URLs longer than 2 kilobytes, for example.
Been trying to get my head around while loops for the last few days but the code seems very inefficient for what I'm trying to achieve. I'm assuming I'm over-complicating this though nothing I've tried seems to work.
Each topic in my forum can have related topic IDs stored in a separate table. A post ID is also stored in this table, as that specific post references why they are considered related.
DB Table contains only: topic_id, related_id, post_id
// Get related IDs and post IDs for current topic being viewed
$result = $db->query('SELECT related_id, post_id FROM related_topics WHERE topic_id='.$id.'');
// If related topics found, put both of the IDs into arrays
if ($db->num_rows($result)) {
while($cur_related = mysql_fetch_array($result)){
$reltopicarray[] = $cur_related['related_id'];
$relpost[] = $cur_related['post_id'];
}
// If the first array isnt empty, get some additional info about each related ID from another table
if(!empty($reltopicarray)) {
$pieces = $reltopicarray;
$glued = "\"".implode('", "', $pieces)."\"";
$fetchtopics = $db->query('SELECT id, subject, author, image, etc FROM topics WHERE id IN('.$glued.')');
}
// Print each related topic
while($related = mysql_fetch_array($fetchtopics)){ ?>
<?php echo $related['subject']; ?> by <?php echo $related['author']; ?>
// Id like to show the Post ID below (from the array in the first while loop)
// The below link doesnt work as Im outside the while loop by this point.
<br />View Relationship
<?php } ?>
The above currently works, however I'm trying to also display the post_id link below each related topic link, as shown above.
if you change the second while loop to something like this:
<?php
$i = 0;
while($related = mysql_fetch_array($fetchtopics)){
//show view link
// [...]
//show the view related link
?>
View Relationship
<?php
//increment the i so that you can get the next post in the next iteration of the loop
$i++;
}
?>
[sidenote]
You probably should not be doing database queries in the same location you are generating the html for future-you's sanity.
[/sidenote]
[edit]
You could also do it all as one query:
SELECT related_topics.related_id,
related_topics.post_id,
related_topics.topic_id,
topics.subject,
topics.author,
topics.image,
topics.etc
FROM related_topics
LEFT JOIN topics ON topics.id = related_topics.topic_id
WHERE topic_id= $id
Then you only have to loop through it once for all of the links.