Forum Moderators: coopster

Message Too Old, No Replies

[PHP/MySQL] Displaying articles =/

         

thijsnetwork

4:55 pm on Jan 23, 2004 (gmt 0)

10+ Year Member



Hello everybody,

I've encountered a problem while coding PHP: The users on my website have their own page where they can post articles. They have the opportunity to publish the articles for everybody (status=4) or publish them only for friends (status=2). Now, what I want is that the script automatically detects whether a user (who is logged in by cookie) is a friend of the author of the articles he is viewing. If so, the articles that are marked by the author with "only visible for friends" must ALSO appear among the other articles :).

Now, the script have to do things like:

- Select the articles that are public, from the author we requested the page from.
- also select the articles that are marked with "only visible to friends", and the logged in user IS a friend of the author.

Well, I've tried to do this with a MySQL query, but I wasn't able to fit all the conditions in one single query, I've got this so far..


"SELECT id FROM articles WHERE status='4' AND author='$USER' ORDER BY date DESC LIMIT $start, $perpage"

and:

// check if the user is a friend of the author...
$reader = $_COOKIE['username'];
"SELECT * FROM friends WHERE user='$USER' AND friend='$reader'"
// if numrows is more than 1, execute this query...
"SELECT id FROM articles WHERE status='2' AND author='$USER'"

// print articles.

Does anybodt knows how to solve this quite nasty problem? Maybe with if and while statements? I don't know where to start. =/

These are the tables I use in my script:


CREATE TABLE `articles` (
`id` int(11) NOT NULL auto_increment,
`author` varchar(50) NOT NULL default '',
`subject` varchar(255) NOT NULL default '',
`article` text NOT NULL,
`date` int(10) NOT NULL default '0',
`status` int(1) NOT NULL default '4',
) TYPE=MyISAM;

CREATE TABLE `friends` (
`id` int(11) NOT NULL auto_increment,
`user` varchar(50) NOT NULL default '',
`friend` varchar(50) NOT NULL default '',
) TYPE=MyISAM;

I'm using Apache 1.3.29 in combination with PHP 4.3.4 and MySQL 3.23.x

jamie

5:16 pm on Jan 23, 2004 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



hi,

couldn't you use WHERE status IN()

check for cookie and depending on that either SELECT WHERE status = 4

or

SELECT WHERE status IN(2, 4)?

coopster

5:33 pm on Jan 23, 2004 (gmt 0)

WebmasterWorld Administrator 10+ Year Member



Welcome to WebmasterWorld, thijsnetwork!

Are your variables $USER and $reader (which is $_COOKIE['username']) the same value? It would seem so to me, unless I'm confused by your post. Here is what I think you may be after:


"SELECT id FROM articles
LEFT JOIN friends ON (articles.author = friends.friend)
WHERE status='4' AND author='$USER'
OR status='2' AND friend = '$reader'
ORDER BY date DESC LIMIT $start, $perpage"

If there is no matching record for the right table in the
ON
or
USING
part in a LEFT JOIN [mysql.com], a row with all columns set to
NULL
is used for the right table -- this is what will make sure that you get your
status='4'
rows returned.

thijsnetwork

5:33 pm on Jan 23, 2004 (gmt 0)

10+ Year Member




hi,

couldn't you use WHERE status IN()

check for cookie and depending on that either SELECT WHERE status = 4

or

SELECT WHERE status IN(2, 4)?

Hi, I don't understand what you mean? Could you explain it to me? I'm quite a n00b in PHP/MySQL scripting :)

[edited by: thijsnetwork at 5:37 pm (utc) on Jan. 23, 2004]

thijsnetwork

5:36 pm on Jan 23, 2004 (gmt 0)

10+ Year Member



The two variables are not the same:

$USER = the author of the article (comes from a get var: $_GET['user'] ) and
$reader = the reader who is logged in.

Salsa

5:57 pm on Jan 23, 2004 (gmt 0)

10+ Year Member



Using a JOIN is more sophisticated and efficient, but a simple approach would be to first determine if the reader is a friend, then:

if ($isFriend == 1) $determinedStatus = "status>=2";
else $determinedStatus = "status=4";

$query = "SELECT id FROM articles WHERE $determinedStatus AND author='$USER' ORDER BY date DESC LIMIT $start, $perpage;";

In any case, because in the table you've defined the status column as int(1) I would lose the quotes around the status number in your query because that represents it as a string, and I would expect it to break the query.

I wish you well,
Salsa

thijsnetwork

6:43 pm on Jan 23, 2004 (gmt 0)

10+ Year Member



I tried the query given by "coopster", but it returned a error message: "Column: 'id' in field list is ambiguous".

coopster

6:54 pm on Jan 23, 2004 (gmt 0)

WebmasterWorld Administrator 10+ Year Member



Oops. It is telling you that the
id
field exists in both tables, therefore you have to qualify it with one of the tables. Try this:

"SELECT articles.id FROM articles
LEFT JOIN friends ON (articles.author = friends.friend)
WHERE status='4' AND author='$USER'
OR status='2' AND friend = '$reader'
ORDER BY date DESC LIMIT $start, $perpage"

jamie

6:59 pm on Jan 23, 2004 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



>> welcome to webmasterworld...

cheers coopster, forgot my manners. been a long day :-)

thijsnetwork says
>> If so, the articles that are marked by the author with "only visible for friends" must ALSO appear among the other articles

doesn't this mean that both articles have to appear. the ones marked status=2 and status=4?

in which case wouldn't an IN() clause work?

thijsnetwork

7:01 pm on Jan 23, 2004 (gmt 0)

10+ Year Member



yeah, that's what I mean! :) I'm now trying to solve the problem with the advice of Salsa.

thijsnetwork

7:10 pm on Jan 23, 2004 (gmt 0)

10+ Year Member



I've solved it! :D Thanks especcialy to Salsa! and thanks for the help from others.

The code:


$reader = $_COOKIE["username"];
$author = $_GET["user"];

// See if the user is a friend.
$query = "SELECT * FROM friends WHERE user = \'$author\' AND friend = \'$reader\'";
$results = mysql($query);

if(!$results)
{
//if not a friend get status=4
$query = "SELECT id,subject, article, date FROM articles WHERE author =\'$author\' AND status=4"
$results = mysql_query($query);
}
else
{
//if a friend get status=4 and 2.
$query = "SELECT id,subject, article, date FROM articles WHERE author=\'$author\' AND status=2 AND status=4"
$results = mysql_query($query);
}

//use the results...

coopster

7:23 pm on Jan 23, 2004 (gmt 0)

WebmasterWorld Administrator 10+ Year Member



That isn't going to work for you, thijsnetwork. It won't return any records because the status can't be '2' as well as '4' at the same time, as you have stated:

$query = "SELECT id,subject, article, date FROM articles WHERE
author=\'$author\' AND status=2 AND status=4"

However...

The two variables are not the same:

$USER = the author of the article (comes from a get var: $_GET['user'] ) and
$reader = the reader who is logged in.


Light bulb came on! OK, I understand what you are stating now. I thought the logged in $USER was the author! You mean the logged in user chooses an author whose articles they want to view. The articles they are capable of viewing include the *everybody* status as well as those that the author considers *friends*.


"SELECT
articles.id,
articles.subject,
articles.article,
articles.date
FROM articles
LEFT JOIN friends ON (articles.author = friends.user)
WHERE status=4 AND author='$USER'
OR status=2 AND author='$USER' AND friend='$reader'
ORDER BY date DESC LIMIT $start, $perpage"

In regards to the integer value being represented as a string:
Actually, it won't break the query because of the way MySQL handles comparison operations [mysql.com].

Salsa

7:39 pm on Jan 23, 2004 (gmt 0)

10+ Year Member



I'm glad it worked, but are you sure? It would seem that in the friend query it should be "status=2 OR status=4". Using "satus=2 AND status=4" would seem to select nothing because status cannot be both 2 AND 4.

Also, at least keep the idea of JOINs in the back of your mind, and plan to bone up on them when you would otherwise have to make queries from within the result sets of previous queries.

I wish you well,
Salsa

thijsnetwork

7:42 pm on Jan 23, 2004 (gmt 0)

10+ Year Member



Thanks in advance

thijsnetwork

7:47 pm on Jan 23, 2004 (gmt 0)

10+ Year Member




I'm glad it worked, but are you sure? It would seem that in the friend query it should be "status=2 OR status=4". Using "satus=2 AND status=4" would seem to select nothing because status cannot be both 2 AND 4.
Yeah, that's right, I've modified the query to (status = 2 OR status = 4)

Salsa

7:50 pm on Jan 23, 2004 (gmt 0)

10+ Year Member



I definitely like you new JOIN, Coopster. That would seem like the way to go.

As far as placing integers in quotes, you can't also do that for INSERTs and UPDATEs can you? That always breaks for me, and I'm very careful to never do it. Maybe I've been unnecessarily cautious when making SELECTions and never noticed that it would work.

I wish you well,
Salsa

thijsnetwork

7:53 pm on Jan 23, 2004 (gmt 0)

10+ Year Member



Yeah, the long function worked! Little modified: "SELECT articles.id, articles.author, articles.status, articles.date FROM articles LEFT JOIN friends ON (articles.author = friends.user) WHERE status= 4 AND author='$USER' OR status=2 AND author='$USER' AND friend='$reader' ORDER BY date DESC LIMIT $start, $perpage"

But, I got another problem!
If the author himself wants to read his own article! With the query you gave me, he cannot see his own article, because he don't has himself as a friend :)

coopster

7:58 pm on Jan 23, 2004 (gmt 0)

WebmasterWorld Administrator 10+ Year Member



Salsa, yes, wrapping integers in quotes will work (with MySQL anyway) on SELECT, INSERT, UPDATE AND DELETE. I use it quite often. It comes in very handy, not having to determine the column type prior to statement building, especially in generic, multiple-table processing scripts.

coopster

8:11 pm on Jan 23, 2004 (gmt 0)

WebmasterWorld Administrator 10+ Year Member



But, I got another problem!
If the author himself wants to read his own article! With the query you gave me, he cannot see his own article, because he don't has himself as a friend

OK, now we can use some of Salsa's logic as well as jamie's
IN
clause. First, we need two different queries. Next, we determine who the logged in user is and if they are trying to view their own articles, then use the appropriate query based on the determination:

$query1 =
"SELECT
articles.id,
articles.author,
articles.status,
articles.date
FROM articles
LEFT JOIN friends ON (articles.author = friends.user)
WHERE status=4 AND author='$USER'
OR status=2 AND author='$USER' AND friend='$reader'
ORDER BY date DESC LIMIT $start, $perpage";
$query2 =
"SELECT
articles.id,
articles.author,
articles.status,
articles.date
FROM articles
LEFT JOIN friends ON (articles.author = friends.user)
WHERE status=IN(2,4) AND author='$USER'
ORDER BY date DESC LIMIT $start, $perpage";
if ($USER == $reader) {
$query = $query2;
} else {
$query = $query1;
}
$results = mysql_query($query);

thijsnetwork

8:17 pm on Jan 23, 2004 (gmt 0)

10+ Year Member



It can easier.. (I'm using a $sqldb class to connect to the database)

if (isset($_COOKIE['username']) && $_GET['user'] == $_COOKIE['username']) {
$result = $sqldb->query("SELECT id, author, status, date FROM articles WHERE author = '$USER' AND (status = 2 OR status= 4) ORDER BY date DESC LIMIT $start, $perpage");
} else {
$result = $sqldb->query("SELECT articles.id, articles.author, articles.status, articles.date FROM articles LEFT JOIN friends ON (articles.author = friends.user) WHERE status= 4 AND author='$USER' OR status=2 AND author='$USER' AND friend='$reader' ORDER BY date DESC LIMIT $start, $perpage");
}

coopster

8:27 pm on Jan 23, 2004 (gmt 0)

WebmasterWorld Administrator 10+ Year Member



You're right, we wouldn't need to perform a LEFT JOIN when the USER is also the author. Good catch. You could also use the
IN
clause where you have the
OR
, as jamie suggested:

if (isset($_COOKIE['username']) && $_GET['user'] == $_COOKIE['username']) {
$result = $sqldb->query("SELECT id, author, status, date FROM articles
WHERE author = '$USER' AND status IN(2,4) ORDER BY date DESC LIMIT $start, $perpage");
} else {
.
.
.

[edited by: coopster at 8:31 pm (utc) on Jan. 23, 2004]

Salsa

8:28 pm on Jan 23, 2004 (gmt 0)

10+ Year Member



Coopster: Hmmm. It sure doesn't work for me, at least on my local WIN setups where I do all testing. Current machine is W2K (5.0 build 2195), MySQL 3.23.49, Apache 1.3.12, PHP 4.3.1. I also have older setups on Win98 and ME, and ints in quotes have always broken queries for me. All are installed from binaries. My Web servers run FreeBSD and are setup from source code, but everything is always tested before it gets there, so I've never seen quoted int results there.

thijsnetwork: Can't you just make all authors their own friends by default?
Also, if you were to use your original query instead of the JOIN, I think you'll have to put the OR part of the statement in () or you will select all articles from all authors where status=4.

I wish you well,
Salsa

thijsnetwork

8:55 pm on Jan 23, 2004 (gmt 0)

10+ Year Member



You're right, we wouldn't need to perform a LEFT JOIN when the USER is also the author. Good catch. You could also use the IN clause where you have the OR, as jamie suggested:

Thanks, I've changed it.

Salsa: By doing that, I have to change a lot of code, (signup script/"friends add"-page/"friends-view"page, etc.) So, this solution is good for me! :)

Salsa

8:59 pm on Jan 23, 2004 (gmt 0)

10+ Year Member



Coopster: I stand corrected. I've been playing around at the command line, and ints in quotes do indeed work for me. It seems that I've misled myself for a long time, and I want to catch myself before I do it to anyone else! I have no idea what I might have been thinking execept perhaps that strings, of course, must be in quotes, and I used some flawed logic from there.

I wish you well.
Salsa

coopster

9:15 pm on Jan 23, 2004 (gmt 0)

WebmasterWorld Administrator 10+ Year Member



Salsa, I'm not saying it's right or wrong, I'm merely stating that, with MySQL, strings are automatically converted to numbers and numbers to strings as needed (as in Perl).

Anybody know the ANSI SQL standard?

coopster

9:33 pm on Jan 23, 2004 (gmt 0)

WebmasterWorld Administrator 10+ Year Member



jamie, you and I were working different sides of the fence at the same time -- I thought the user was the author, you thought the user was selecting a different author -- and all the while both solutions were eventually needed anyway!

forgive me if you already understand, but I started the response as soon as you posed the question back in msg#9. I decided to post it anyway :)



The reason the
IN
clause will not work is because there is a compound comparison going on. The articles can be viewed if and only if both the following are true:
  1. The author has made the article available to everybody (status=4)
  2. The author has made the article available to friends only (status=2 and friend='my friend')

There is a level of separation involving two tables that can't be accomplished using an

IN
clause. Let me try to show you an example. First, let's agree on the query we might use:

"SELECT articles.id FROM articles
LEFT JOIN friends ON (articles.author = friends.user)
WHERE status IN(2,4) AND author='$USER' AND friend='$reader'
ORDER BY date DESC LIMIT $start, $perpage"

Now, let's say the user logged in is not a *friend* of the author. No results would be returned. Why not? Well, we obviously wouldn't get any status=2 records because they aren't a friend of the author. But why not status=4 records? Same reason.

jamie

6:40 am on Jan 24, 2004 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



coopster,

it's often tricky getting your head round someone else' problem - and no i didnt completely understand the question.

now i do :-)

having sat down and looked at it, i realise the IN wouldn't work either - probably would have taken me a frustrating few tries though ;-)

thanks for explaining

thijsnetwork

9:08 am on Jan 24, 2004 (gmt 0)

10+ Year Member



Hi guys,

I got another issue with the new friends system ;) I always had a list of the 5 newest articles, which I generate with a query like this:


$this->query('SELECT * FROM articles WHERE status IN(1,4) ORDER BY date DESC LIMIT 0, ' . $howMany);

Status 1 is a newsitem, that appears on the frontpage.

Well, now I want that also articles appear who are written only for friends, but not ALL the articles that have status=2, but ONLY the articles of which the reader is a friend of the author. And if not, the article will not appear in the list. So the difference here is, you got to do with more than onw author.

Does somebody knows how to solve this, and what kind of query I need?

coopster

3:53 pm on Jan 24, 2004 (gmt 0)

WebmasterWorld Administrator 10+ Year Member



If I am understanding you correctly, it would be the same query as before, just change your WHERE clause to drop the author-based comparison:

WHERE status=2 AND friend='$reader'

thijsnetwork

4:02 pm on Jan 24, 2004 (gmt 0)

10+ Year Member



What do you mean? The "articles" table contains not a "friend" column. Could you give the full query.. :)
This 57 message thread spans 2 pages: 57