문제

I'm creating a simple blog. I have created 2 tables. First one lists all of the articles with relevant columns (articleID, articleTitle, articleAuthor, etc) Second one lists all of the comments with relevant columns (commentID, articleID, commentName, etc)

On the blog page I am using a recordset to display each artcle with a simple SELECT * from articles and ordering it by DESC date.

Now, I am trying to pair up the correct comments below each article using a new recordset that joins the tables articles and comments on articleID.

my issue is that each article is return only the first comment listed. I don't know if I need a runtime variable, or what. I've read so many different blogs and forums and got some many different answers that I got lost in it all and it stopped making sense.

I am pretty sure that there are many ways to do this but also quite sure that this is a common thing to do so it should't be too hard to create. I just need some advice.

I can provide more details as needed.

Many thanks in advance!

    <?php
if (!function_exists("GetSQLValueString")) {
function GetSQLValueString($theValue, $theType, $theDefinedValue = "", $theNotDefinedValue = "") 
{
  if (PHP_VERSION < 6) {
    $theValue = get_magic_quotes_gpc() ? stripslashes($theValue) : $theValue;
  }

  $theValue = function_exists("mysql_real_escape_string") ? mysql_real_escape_string($theValue) : mysql_escape_string($theValue);

  switch ($theType) {
    case "text":
      $theValue = ($theValue != "") ? "'" . $theValue . "'" : "NULL";
      break;    
    case "long":
    case "int":
      $theValue = ($theValue != "") ? intval($theValue) : "NULL";
      break;
    case "double":
      $theValue = ($theValue != "") ? doubleval($theValue) : "NULL";
      break;
    case "date":
      $theValue = ($theValue != "") ? "'" . $theValue . "'" : "NULL";
      break;
    case "defined":
      $theValue = ($theValue != "") ? $theDefinedValue : $theNotDefinedValue;
      break;
  }
  return $theValue;
}
}

$maxRows_rsArticle = 10;
$pageNum_rsArticle = 0;
if (isset($_GET['pageNum_rsArticle'])) {
  $pageNum_rsArticle = $_GET['pageNum_rsArticle'];
}
$startRow_rsArticle = $pageNum_rsArticle * $maxRows_rsArticle;

mysql_select_db($database_PowerStoreConnection, $PowerStoreConnection);
$query_rsArticle = "SELECT ArtID, ArtTitle, ArtPubDate, ArtDesc, ArtAuthor, ArtContent FROM blog_articles WHERE BlogID = 1 ORDER BY ArtPubDate DESC";
$query_limit_rsArticle = sprintf("%s LIMIT %d, %d", $query_rsArticle, $startRow_rsArticle, $maxRows_rsArticle);
$rsArticle = mysql_query($query_limit_rsArticle, $PowerStoreConnection) or die(mysql_error());
$row_rsArticle = mysql_fetch_assoc($rsArticle);

if (isset($_GET['totalRows_rsArticle'])) {
  $totalRows_rsArticle = $_GET['totalRows_rsArticle'];
} else {
  $all_rsArticle = mysql_query($query_rsArticle, $PowerStoreConnection);
  $totalRows_rsArticle = mysql_num_rows($all_rsArticle);
}
$totalPages_rsArticle = ceil($totalRows_rsArticle/$maxRows_rsArticle)-1;

$paramArtID_rsComment = "-1";
if (isset($_GET['blog_articles.ArtID'])) {
  $paramArtID_rsComment = $_GET['blog_articles.ArtID'];
}
mysql_select_db($database_PowerStoreConnection, $PowerStoreConnection);
$query_rsComment = sprintf("SELECT blog_comments.artID, comName, comEmail, comWebsite, blog_comments.comment, comDate FROM blog_comments JOIN blog_articles ON  blog_articles.ArtID = blog_comments.artID WHERE blog_comments.artID = %s ORDER BY comDate DESC", GetSQLValueString($paramArtID_rsComment, "int"));
$rsComment = mysql_query($query_rsComment, $PowerStoreConnection) or die(mysql_error());
$row_rsComment = mysql_fetch_assoc($rsComment);
$totalRows_rsComment = mysql_num_rows($rsComment);
?>

I am adding the full page code below so someone could possibly point out how to use the code that was provided in the answer. It's my goal to learn this in the days to come so at least when I come back here for help I will at least know what this means and be able to ask better questions. Maybe someday I will understand this enough to repay the favor or help others.

Thank you!

<?php require_once('Connections/PowerStoreConnection.php'); ?>
<!--ARTICLE CONTENT-->
<?php
if (!function_exists("GetSQLValueString")) {
function GetSQLValueString($theValue, $theType, $theDefinedValue = "", $theNotDefinedValue = "") 
{
  if (PHP_VERSION < 6) {
    $theValue = get_magic_quotes_gpc() ? stripslashes($theValue) : $theValue;
  }

  $theValue = function_exists("mysql_real_escape_string") ? mysql_real_escape_string($theValue) : mysql_escape_string($theValue);

  switch ($theType) {
    case "text":
      $theValue = ($theValue != "") ? "'" . $theValue . "'" : "NULL";
      break;    
    case "long":
    case "int":
      $theValue = ($theValue != "") ? intval($theValue) : "NULL";
      break;
    case "double":
      $theValue = ($theValue != "") ? doubleval($theValue) : "NULL";
      break;
    case "date":
      $theValue = ($theValue != "") ? "'" . $theValue . "'" : "NULL";
      break;
    case "defined":
      $theValue = ($theValue != "") ? $theDefinedValue : $theNotDefinedValue;
      break;
  }
  return $theValue;
}
}

$maxRows_rsArticle = 10;
$pageNum_rsArticle = 0;
if (isset($_GET['pageNum_rsArticle'])) {
  $pageNum_rsArticle = $_GET['pageNum_rsArticle'];
}
$startRow_rsArticle = $pageNum_rsArticle * $maxRows_rsArticle;

mysql_select_db($database_PowerStoreConnection, $PowerStoreConnection);
$query_rsArticle = "SELECT ArtID, ArtTitle, ArtPubDate, ArtDesc, ArtAuthor, ArtContent FROM blog_articles WHERE BlogID = 1 ORDER BY ArtPubDate DESC";
$query_limit_rsArticle = sprintf("%s LIMIT %d, %d", $query_rsArticle, $startRow_rsArticle, $maxRows_rsArticle);
$rsArticle = mysql_query($query_limit_rsArticle, $PowerStoreConnection) or die(mysql_error());
$row_rsArticle = mysql_fetch_assoc($rsArticle);

if (isset($_GET['totalRows_rsArticle'])) {
  $totalRows_rsArticle = $_GET['totalRows_rsArticle'];
} else {
  $all_rsArticle = mysql_query($query_rsArticle, $PowerStoreConnection);
  $totalRows_rsArticle = mysql_num_rows($all_rsArticle);
}
$totalPages_rsArticle = ceil($totalRows_rsArticle/$maxRows_rsArticle)-1;

$paramArtID_rsComment = "-1";
if (isset($_GET['blog_articles.ArtID'])) {
  $paramArtID_rsComment = $_GET['blog_articles.ArtID'];
}
mysql_select_db($database_PowerStoreConnection, $PowerStoreConnection);
$query_rsComment = sprintf("SELECT blog_comments.artID, comName, comEmail, comWebsite, blog_comments.comment, comDate FROM blog_comments JOIN blog_articles ON  blog_articles.ArtID = blog_comments.artID WHERE blog_comments.artID = %s ORDER BY comDate DESC", GetSQLValueString($paramArtID_rsComment, "int"));
$rsComment = mysql_query($query_rsComment, $PowerStoreConnection) or die(mysql_error());
$row_rsComment = mysql_fetch_assoc($rsComment);
$totalRows_rsComment = mysql_num_rows($rsComment);
?>
<!--//ARTICLE CONTENT-->
<?php
require_once('webassist/themes/theme_open.php');
$WAIncludeContent = new WA_Include(__FILE__);
?>
<html>
<head>
<title>Blog</title>
</head>
<body> 
        <h1>Blog</h1>
      <div class="contentBox pod1 borderColor">
        <?php do { ?>
        <h2><?php echo $row_rsArticle['ArtTitle']; ?></h2>
       <div class="articles" style="background-color:#FFF"><h3>Posted - <?php echo date('M d, Y' ,strtotime($row_rsArticle['ArtPubDate'])); ?></h3>
        <h3> By <?php echo $row_rsArticle['ArtAuthor']; ?> | x Comments</h3>
        <p><?php echo $row_rsArticle['ArtContent']; ?></p>
       </div>

        <h3>Comments:</h3>
        <p><strong>Name <?php echo $row_rsComment['comName']; ?></strong> | <a href="<?php echo $row_rsComment['comWebsite']; ?>" target="_blank">Website</a> |  | <a href="#">Reply</a><br>
        <strong>Submitted - <?php echo date('M d, Y' ,strtotime($row_rsComment['comDate'])); ?></strong><br>
        <br><?php echo $row_rsComment['comment']; ?>        </p>


          <?php } while ($row_rsArticle = mysql_fetch_assoc($rsArticle)); ?>
      </div>    

</body>
</html>
<?php
mysql_free_result($rsArticle);

mysql_free_result($rsComment);
?>
<?php require_once('webassist/themes/theme_close.php'); ?>

올바른 솔루션이 없습니다

다른 팁

You are only fetching the first row. You have to fetch all the rows. You can do this using a loop.

I will be showing you how to use the "while" loop using mysqli instead of mysql_, because mysql_ is deprecated. (By the way, you should also be aware that PowerStore's code is full of security holes, including with mysql_, partially because hackers know what all the functions are and partially because they have half-baked database security. In particular, you really need to replace their image uploader security ASAP because it is very easily exploitable.)

From the mysqli pages of the PHP manual (prepare, bind_param, get_result):

<?php
$link = mysqli_connect("localhost", "my_user", "my_password", "world");

/* check connection */
if (mysqli_connect_errno()) {
    //NOTE: while this is in the manual, you should do your own error handling
    printf("Connect failed: %s\n", mysqli_connect_error());
    exit();
}

//Use question marks for prepared statements
$query = "SELECT ArtID, ArtTitle, ArtPubDate, ArtDesc, ArtAuthor, ArtContent 
    FROM blog_articles 
    WHERE BlogID = 1 
    ORDER BY ArtPubDate DESC
    LIMIT ?, ?";

if($stmt = mysqli_prepare($link, $query)) {
    //This next line does everything from GetSQLValueString and more!
    mysqli_stmt_bind_param($stmt, "ii", $startRow_rsArticle, $maxRows_rsArticle);

    mysqli_stmt_execute();

    $result = mysqli_stmt_get_result($stmt);

    //This is where all your rows will go
    $allRows = array();

    //This is your loop
    while ($row = mysqli_fetch_assoc($result)) {
        $allRows[] = $row;
    }

    /* close statement */
    mysqli_stmt_close($stmt);
} else {
    //handle what happens when there is no result
}

/* close connection */
mysqli_close($link);


/*** Later in your code ***/
foreach($allRows as $row) {
     //do whatever you're doing with each row of information
}
?>

Note that your prepared statement for your other query would go like this:

$query = "SELECT blog_comments.artID, comName, comEmail, comWebsite, 
    blog_comments.comment, comDate 
    FROM blog_comments 
    JOIN blog_articles ON  blog_articles.ArtID = blog_comments.artID 
    WHERE blog_comments.artID = ? 
    ORDER BY comDate DESC";

if($stmt = mysqli_prepare($link, $query)) {
    mysqli_stmt_bind_param("i", $paramArtID_rsComment);
    ....

EDIT

Okay, I see what you're trying to do now. Let me show you how to get the comments you are looking for. I am going to use one query to get all the comments because the fewer queries you make, the better. On many cheap server packages (I assume that's what you have), querying the database takes more time than it should due to connection speed issues between the database and the web scripts.

How do I use one query? First, I am going to make one tiny change to collecting the articles. I will make the keys of the $allRows array the article ids.

    //This is your loop
    while ($row = mysqli_fetch_assoc($result)) {
        $allRows[$row['ArtID']] = $row;
    }

To get the ids back out for my query, I will use this:

 implode(',', array_keys($allRows));

If my article ids are 12, 15, 38, and 44, that would result in this string:

 12,15,38,44

Next, I make my comments query. I can't use a prepared statement for this query because I want to use a list of numbers, not just one number. But it's safe for me to use a non-prepared statement here because I know that the values are all integers that I have gotten straight from another query. If they were not known values (i.e., a user entered them originally), I would use mysqli_real_escape_string on each value before putting it in the array above.

From the mysqli page of the PHP manual for mysqli_query:

$query = sprintf("SELECT blog_comments.artID, comName, comEmail, comWebsite, 
    blog_comments.comment, comDate 
    FROM blog_comments 
    JOIN blog_articles ON  blog_articles.ArtID = blog_comments.artID 
    WHERE blog_comments.artID IN (%s) 
    ORDER BY comDate DESC",
    implode(',', array_keys($allRows))
    );

if($result = mysqli_query($link, $query, MYSQLI_USE_RESULT) {
    while ($row = mysqli_fetch_assoc($result)) {
        //I am going to create a 'Comments' array in each article row
        //This is a "multidimensional array", fyi
        $allRows[$row['artID']]['Comments'][] = $row;
    }
    mysqli_free_result($result);
} else if(mysqli_errno($link)) {
    //an example of error handling
    //you should do this after every query to check for errors
    throw new Exception(mysqli_error($link), mysqli_errno($link));
}

Now that I have collected the information, I can call 'mysqli_close()' and close the database connection.

<html>
<head>
<title>Blog</title>
</head>
<body> 
  <h1>Blog</h1>
  <?php
  //Here is where we make use of the array from earlier
  if(sizeof($allRows) == 0) {  // there are no articles
      ?>
      <h2>No articles found.</h2>
      </php
  } else {  // there is at least one article
    foreach($allRows as $row) { //start article loop
    ?>
    <div class="contentBox pod1 borderColor">
      <h2><?php echo $row['ArtTitle']; ?></h2>
      <div class="articles" style="background-color:#FFF"><h3>Posted - <?php echo date('M d, Y' ,strtotime($row['ArtPubDate'])); ?></h3>
        <h3> By <?php echo $row['ArtAuthor']; ?> | x Comments</h3>
        <p><?php echo $row['ArtContent']; ?></p>
      </div>

      <h3>Comments:</h3>
      <?php
      if(sizeof($row['Comments']) == 0) { // there are no comments
         ?>
         <p>No comments.</p>
         <?php
      } else {
        //Let's get the comments out
         foreach($row['Comments'] as $comment) { //start comment loop
          ?>
          <p><strong>Name <?php echo $comment['comName']; ?></strong> 
             | <a href="<?php echo htmlspecialchars($comment['comWebsite']); ?>" target="_blank">Website</a> |  
             | <a href="#">Reply</a><br>
             <strong>Submitted - <?php echo date('M d, Y' ,strtotime($comment['comDate'])); ?></strong><br>
             <br><?php echo $comment['comment']; ?>
          </p>
          <?php
         } // end comment loop
       } // end comment if-else

       //You probably want something here for adding new comments

       ?>
    </div> 
    <?php
    } // end article loop
  } // end article if-else
  ?>   
</body>
</html>

As an additional note, when people add comments, make sure you sanitize them of anything and everything that might load a script when it's echoed on the page. If I were you, because you have so little expertise, I would simply use strip_tags on each comment before saving it to the database.

If you change GetSQLValueString to use mysqli_real_escape_string instead of mysql_real_escape_string, you'll be able to change over to mysqli_query across the board easily, but I strongly suggest using prepared statements where applicable. They make it much, much more difficult to use SQL injection on you.
The connection stuff at the top of my example should be used in place of the PowerStore connection stuff. You'll have to change all the mysql across the entire site, but it's worth it in database connection handling alone (on my server, the deprecated mysql functions caused database lockups on a regular basis, rendering the site inoperable for minutes or hours at a time). If the connection fails, you should redirect to an error page of your own making that says something like "Server Error blah blah blah" on it and that makes no database calls. Here's an example:

/* check connection */
if (mysqli_connect_errno()) {
    throw new Exception(mysqli_connect_errno().' '.mysqli_connect_error(), -1000);
}

Also look into proper error handling instead of that die() crap that PowerStore and the PHP manual use. You should throw exceptions whenever a mysql error occurs, and use both try-catch and a registered exception handler to handle those and other exceptions. I have my exception handler email me the errors so that I am alerted to them. An example that handles the connection errors from above:

error_reporting(E_ALL); // record all error types
ini_set('display_errors','0'); // don't show errors to your users!

function error_email($errno, $errstr, $errfile, $errline, $errcontext) {
    //email to self
    //I use this array method to get things easier to read
    $message = array();
    $message[] = 'Error: '.$errno.' '.$errstr;
    $message[] = 'File '.$errfile.' Line '.$errline;
    $message[] = implode("\r\n",$errcontext);

    error_log(implode("\r\n\r\n",$message), 1, "myemail@mydomain.com");
}

function exception_handler($e) {
    if($e->getCode() == -1000) {
        if(headers_sent()) {
            header('Location: http://mydomain.com/500Error.php');
        } else {
            include('error_message.php');
        }
        exit();
    } else {
        include('error_message.php');
    }
    //email to self
    error_email($e->getCode(), $e->getMessage(), $e->getFile(), $e->getLine(), $e->getTrace());
    die();
}
set_exception_handler('exception_handler');

function error_handler($errno,$errstr,$errfile,$errline,$errcontext) {
    error_email($errno, $errstr, $errfile, $errline, $errcontext);
    include('error_message.php');
    die();
}
set_error_handler('error_handler');
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top