News:

SMF 2.1.4 has been released! Take it for a spin! Read more.

Main Menu

need help with ssi codeing to Random

Started by johny000, September 07, 2009, 05:13:07 PM

Previous topic - Next topic

johny000

hello guys how are you all
i'm usering smf v1.1.10
i'm trying  to make this ssi code work as Random

like it will chenge Random to the next post




<?php
// Require SSI
require('SSI.php');
echo 
'
<META http-equiv=Content-Type content="text/html; charset=windows-1256">
<META http-equiv=Content-Language content=ar-sy>
'
;
// Some variables. Change these to test this script :)
$boards = array(158); // Boards to use
$number 2// Number of items to return
$length 70// Return this number of characters, followed by "...".

// Get the news
$news_items ssi_boardNews($boards$numbernull$length'array'); // array(boards), number of items, item to start at, number of characters, output method
// Loop through all items
foreach ($news_items as $news)
{
// Output this item
echo '<bdo dir="rtl">
<div>

<div class="post" style="padding: 2ex 0;"><a target="_blank" href="'
$news['href'], '" style="text-decoration: none">'$news['body'], '</a></p></div>

<a target="_blank" href="'
$news['href'], '" style="text-decoration: none"><FONT COLOR="black" >&#38;#x2022;</FONT>&nbsp;'$news['subject'], '</a>
</div>'
;

// If it isn't the last item, output a <hr />
if (!$news['is_last'])
echo '
<hr style="margin: 1ex 0;" width="100%" />'
;
}
?>


any one can do it plezz  thank you

Arantor

I'm not sure I follow what you want... do you want a random post from the given board, or a random topic, or even a random board to be picked out of a list?

johny000

i want a random post from the given board 
Quote from: Arantor on September 07, 2009, 05:26:15 PM
I'm not sure I follow what you want... do you want a random post from the given board, or a random topic, or even a random board to be picked out of a list?

Arantor

A random individual post, could be anywhere from any topic in that board? I don't think it's doable from SSI, meaning a raw DB query.

Which version of SMF?

johny000

yes any topic in that board
smf version 1.1.10


Quote from: Arantor on September 07, 2009, 06:06:01 PM
A random individual post, could be anywhere from any topic in that board? I don't think it's doable from SSI, meaning a raw DB query.

Which version of SMF?

SoLoGHoST

#5
Hello, you would have to modify the SSI.php file.  I would create a function and make it similar to the ssi_recentTopics function.  Instead of an exclude_boards parameter, have an include_boards parameter (which you can keep as an array no problem) and instead of:
AND b.ID_BOARD NOT IN (" . implode(', ', $exclude_boards) . ")") . "
change it to:
AND b.ID_BOARD IN (" . implode(', ', $include_boards) . ")") . "

Or if you want you can even just add onto this function and add 2 parameters...
function ssi_recentTopics($num_recent = 8, $exclude_boards = null, $include_boards = null, $random = false, $output_method = 'echo')

So we added $include_boards and $random.  Setup the $include_boards variable exactly like the $exclude_boards variable.

Then you can use the mt_rand() PHP Function to get a random id between the minimum topic id for that board to the maximum topic id for that board by querying the topics table and getting all relevant topic ids for each board id inside of the $include_boards variable which will become an array.  Or you can build an array from all topic ids within that board(s) and call upon 1 of these values inside of the array by a random index (again using mt_rand(0, count($array) - 1).

Cheers :)

Arantor

Except that topic ids in a board are not contiguous, so this suddenly gets *very* expensive to calculate because you can't just pick min and max and have a number in between.

You will not be able to do this efficiently - in SSI.php functions or not.

The most efficient you'll be able to do, is outside SSI.php in your own code, doing the following:
1. Query the DB to get the number of potential posts - n posts.
2. Select a random number from 0 to n-1.
3. Get that post.

You do NOT use ORDER BY RANDOM(), this is a fair chunk faster, though you do 2 db queries.

You could do this with:


<?php
include ('SSI.php');

$boards = array(1); // or whatever

$query db_query("
  SELECT COUNT(*) FROM 
{$db_prefix}messages WHERE ID_BOARD IN (" implode(', '$boards) . ")
"
__FILE____LINE__);

$entry 0;
if(
$row mysql_fetch_row($query)) {
  
$entry mt_rand(0$row[0]-1);
}
mysql_free_result($query);

$query db_query("
  SELECT * FROM 
{$db_prefix}messages
  WHERE ID_BORAD IN (" 
implode(', '$boards) . ")
  ORDER BY NULL,
  LIMIT 
{$entry},1
"
__FILE____LINE__);

if(
$row mysql_fetch_assoc($query)) {
  
// $row = nice friendly array of content about the message, including its title, board id, and much more,
  // see the messages table for a complete list of what you get
}
?>


SoLoGHoST

Yeah, that's why I edited it to say, build an array of topic ids within that board.  Than select a random index from the array from 0 to (count($array) - 1).  That would do it just perfect.

Cheers :)

SoLoGHoST

#8
This would return all messages, included in topics also.  Such as replies also.

EDIT
Opps, just now seeing you want all messages.  Definitely use the messages table in that case than.

Cheers :)

Arantor

You could build an array, but the effort in selecting a large list (more than 100 items or so) is outweighed as you bring them back to PHP to pick one. The code I posted is about the fastest way you can do it when you get beyond a small number of items.

SoLoGHoST

Ok, I see what you are doing, took me a little bit to see it.  Nice, you are grabbing the last $row for mt_rand.  Didn't think about this.

Just curious, why are you ordering by NULL though?

johny000

idid not get this
The most efficient you'll be able to do, is outside SSI.php in your own code, doing the following:
1. Query the DB to get the number of potential posts - n posts.
2. Select a random number from 0 to n-1.
3. Get that post.

i have made new php file & post the code you give me  now is giveing me  Error

You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near 'LIMIT 43,1' at line 4
File: htdocs/smf/fnews1.php
Line: 21

& the  Line: 21 is >>>>>     ", __FILE__, __LINE__); 

Quote from: Arantor on September 07, 2009, 08:40:34 PM
Except that topic ids in a board are not contiguous, so this suddenly gets *very* expensive to calculate because you can't just pick min and max and have a number in between.

You will not be able to do this efficiently - in SSI.php functions or not.

The most efficient you'll be able to do, is outside SSI.php in your own code, doing the following:
1. Query the DB to get the number of potential posts - n posts.
2. Select a random number from 0 to n-1.
3. Get that post.

You do NOT use ORDER BY RANDOM(), this is a fair chunk faster, though you do 2 db queries.

You could do this with:


<?php
include ('SSI.php');

$boards = array(1); // or whatever

$query db_query("
  SELECT COUNT(*) FROM 
{$db_prefix}messages WHERE ID_BOARD IN (" implode(', '$boards) . ")
"
__FILE____LINE__);

$entry 0;
if(
$row mysql_fetch_row($query)) {
  
$entry mt_rand(0$row[0]-1);
}
mysql_free_result($query);

$query db_query("
  SELECT * FROM 
{$db_prefix}messages
  WHERE ID_BORAD IN (" 
implode(', '$boards) . ")
  ORDER BY NULL,
  LIMIT 
{$entry},1
"
__FILE____LINE__);

if(
$row mysql_fetch_assoc($query)) {
  
// $row = nice friendly array of content about the message, including its title, board id, and much more,
  // see the messages table for a complete list of what you get
}
?>



Arantor

SoLoGHoST: ORDER BY NULL forces it not to order, so you avoid hitting a filesort (which it will normally trigger otherwise, AFAIK). Then again depending on the table makeup, ORDER BY ID_TOPIC may by fractionally faster.

johny000: The process I outlined is the ONLY semi-efficient way to get what you're after.

The reason it fails is because I made a typo - ORDER BY NULL shouldn't have a comma after it.

SoLoGHoST

#13
You can get rid of the {$entry} in there, but keep LIMIT 1... and do:


$query = db_query("
  SELECT * FROM {$db_prefix}messages
  WHERE ID_BORAD IN (" . implode(', ', $boards) . ")
  ORDER BY NULL", __FILE__, __LINE__);

$x = 0;

while ($row = mysql_fetch_assoc($query)) {
if ($entry == $x)
{
// do the stuff...
}

$x++;
}


EDIT:  Just another way of doing it, but Arantor's approach is a bit better IMO.

johny000

so you telling me ihave to edit? like this

<?php
include ('SSI.php');

$boards = array(1); // or whatever

$query db_query("
  SELECT COUNT(*) FROM 
{$db_prefix}messages WHERE ID_BOARD IN (" implode(', '$boards) . ")
"
__FILE____LINE__);

$entry 0;
if(
$row mysql_fetch_row($query)) {
  
$entry mt_rand(0$row[0]-1);
}
mysql_free_result($query);

$query db_query("
  SELECT * FROM 
{$db_prefix}messages
  WHERE ID_BORAD IN (" 
implode(', '$boards) . ")
  ORDER BY NULL,
  LIMIT 1
"
__FILE____LINE__);

$x 0;

while (
$row mysql_fetch_assoc($request)) {
if (
$entry == $x)
{
// do the stuff...
}

$x++;
}
?>




Quote from: SoLoGHoST on September 07, 2009, 09:22:32 PM
You can get rid of the {$entry} in there, but keep LIMIT 1... and do:


$query = db_query("
  SELECT * FROM {$db_prefix}messages
  WHERE ID_BORAD IN (" . implode(', ', $boards) . ")
  ORDER BY NULL
  LIMIT 1
", __FILE__, __LINE__);

$x = 0;

while ($row = mysql_fetch_assoc($query)) {
if ($entry == $x)
{
// do the stuff...
}

$x++;
}


EDIT:  Just another way of doing it, but Arantor's approach is a bit better IMO.

SoLoGHoST

#15
No no, use arantor's approach, if you wanna use mine that's fine, just change that query at the end.

BYTHEWay, doing this really quick as I'm in between things atm, if you use my approach, just get rid of the LIMIT 1.

Also, get rid of the ORDER BY NULL.  So it will look like this:
<?php
include ('SSI.php');

$boards = array(1); // or whatever

$query db_query("
  SELECT COUNT(*) FROM 
{$db_prefix}messages WHERE ID_BOARD IN (" implode(', '$boards) . ")
"
__FILE____LINE__);

$entry 0;
if(
$row mysql_fetch_row($query)) {
  
$entry mt_rand(0$row[0]-1);
}
mysql_free_result($query);

$query db_query("
  SELECT * FROM 
{$db_prefix}messages
  WHERE ID_BORAD IN (" 
implode(', '$boards) . ")"__FILE____LINE__);

$x 0;

while (
$row mysql_fetch_assoc($query)) {
if (
$entry == $x)
{
// do the stuff...
}

$x++;
}
?>



johny000

i did it & herewhat Error i'm geting now

Unknown column 'ID_BORAD' in 'where clause'
File: /homepageshtdocs/smf/fnews1.php
Line: 18


Quote from: SoLoGHoST on September 07, 2009, 09:31:01 PM
No no, use arantor's approach, if you wanna use mine that's fine, just change that query at the end.

BYTHEWay, doing this really quick as I'm in between things atm, if you use my approach, just get rid of the LIMIT 1.

Also, get rid of the ORDER BY NULL.  So it will look like this:
<?php
include ('SSI.php');

$boards = array(1); // or whatever

$query db_query("
  SELECT COUNT(*) FROM 
{$db_prefix}messages WHERE ID_BOARD IN (" implode(', '$boards) . ")
"
__FILE____LINE__);

$entry 0;
if(
$row mysql_fetch_row($query)) {
  
$entry mt_rand(0$row[0]-1);
}
mysql_free_result($query);

$query db_query("
  SELECT * FROM 
{$db_prefix}messages
  WHERE ID_BORAD IN (" 
implode(', '$boards) . ")"__FILE____LINE__);

$x 0;

while (
$row mysql_fetch_assoc($request)) {
if (
$entry == $x)
{
// do the stuff...
}

$x++;
}
?>




Arantor

The problem with that approach is that you have to pull potentially thousands of rows from the database, versus a single row.

It'll work, but when you have a large number of rows, you'll find it'll get increasingly inefficient. And if you are going to iterate through the rowset, *definitely* leave ORDER BY NULL in. You're doing a table scan as it is. Tell MySQL that's what you want.


What's in the forum error log?

johny000

Unknown column 'ID_BORAD' in 'where clause'
File: /homepageshtdocs/smf/fnews1.php
Line: 18

Quote from: Arantor on September 07, 2009, 09:42:03 PM
The problem with that approach is that you have to pull potentially thousands of rows from the database, versus a single row.

It'll work, but when you have a large number of rows, you'll find it'll get increasingly inefficient. And if you are going to iterate through the rowset, *definitely* leave ORDER BY NULL in. You're doing a table scan as it is. Tell MySQL that's what you want.


What's in the forum error log?

Arantor

There was a typo in SoLoGHoST's code, it should have read ID_BOARD.

Advertisement: