phpif-statementwhile-loopisset

Output Component With A While Loop Even If The Component Content Is Empty - PHP


I have a while loop that outputs three images onto an image preview board. This aspect is all working OK. I would like it so that if a preview board has no allocated images it still outputs the board component, but displays a message such as 'Add images to this board'.

In the code below, if the board preview component (the <figure>element) is empty, it currently outputs an unwanted single empty <img> tag. I thought I could fix this by changing this code block:

if ($imgcount < 3) { 
    echo "
        <img src='{$dbImageFile}'>
    ";
}

to this:

// only allow 3 images per board
if ($imgcount < 3 && isset($dbImageFile)) { 
    echo "
        <img src='{$dbImageFile}'>
    ";
}

// echo empty string if no image for this board
if ($imgcount < 3 && !isset($dbImageFile)) { 
    echo "";
}

...which I thought would output an empty string instead of the unwanted single <img> tag if the board has no images allocated to it. This single image tag is missing the filename from its path (although I obviously want to stop this image tag being outputted completely)

And then at the end of the while loop, add the following message when there are no images (this is currently commented out in the main code)

if ($imgcount == 0 ) {
    echo "Add Images To This board";
}

In the MySQL code the boards_images table is a linking/pivot table that holds the board id and a related image id for that board.

<?php
    $s = "SELECT boards.board_name, boards.board_id, images.filename
    FROM boards
    LEFT JOIN boards_images on boards_images.board_id = boards.board_id
    LEFT JOIN images        on boards_images.image_id = images.image_id
    WHERE boards.user_id = :user_id
    ORDER BY boards.board_id";

    $stmt = $connection->prepare($s);
    $stmt -> execute([
        ':user_id' => $db_id // $_SESSION login variable
    ]);

    $dbBoardname_last = '';
    $imgcount = 0;

    while ($row = $stmt->fetch()) {

        $dbBoardId = htmlspecialchars($row['board_id']);
        $dbBoardname = htmlspecialchars($row['board_name']);
        $dbImageFile = htmlspecialchars($row['filename']);

        // close the previousboard component <figure>
        if($dbBoardname_last != '' && $dbBoardname != $dbBoardname_last) {
        echo "
            </figure>
        ";
        }

        //if the board name is the different to the previous one add the opening component tag
        if($dbBoardname != $dbBoardname_last) {
        
            //reset the image count for new boards
            $imgcount = 0;

            // output opening board component <figure>
            echo "
                <figure class='board-component'>
                    <h2>{$dbBoardname}</h2>
            ";
                
        }

        // only allow 3 images per board
        if ($imgcount < 3) { 
            echo "
                <img src='{$dbImageFile}'>
            ";
        }

        $imgcount+=1;
        
        //record the last board_name to check if a new board element should be created

        $dbBoardname_last = $dbBoardname;

        // *** IF NO IMAGES ARE PRESENT ECHO THE 'ADD IMAGES' MESSAGE ***
        // if ($imgcount == 0 ) {
        //     echo "Add Images To this board";
        // }

    } 
    
    // close the last board component element
    if ($dbBoardname_last != '') {
        echo "
        </figure>
        ";
    }
?>

Solution

  • When a board has no images linked to it, MySQL populates the filename value with NULL. And, when a NULL value is passed to the PHP htmlspecialchars() function, it returns an empty string.

    // when "filename" from the database is NULL, $dbImageFile is assigned an empty string.
    $dbImageFile = htmlspecialchars($row['filename']); 
    

    Also PHP isset() function returns true when it is passed a variable that contains an empty string. Therefore the condition if ($imgcount < 3 && isset($dbImageFile)) { writes the image tag when there is no image linked to the board.

    When using htmlspecialchars() you'll never get a NULL, and MySQL always returns "filename" as a declared variable, even when it is assigned NULL. That's why isset() does not do what you expect with $dbImageFile.

    Either use the value, possibly containing NULL, returned in the MySQL results set. $row['filename']:

    // only allow 3 images per board
    if ($imgcount < 3 && isset($row['filename'])) { 
        echo "
            <img src='{$dbImageFile}'>
        ";
    }
    

    ...or, check for an empty string, "" !== $dbImageFile:

    // only allow 3 images per board
    if ($imgcount < 3 && "" !== $dbImageFile) { 
        echo "
            <img src='{$dbImageFile}'>
        ";
    }
    

    This is all you need. You don't need the second if condition with another "less than 3 images written to the board" check, and if the $dbImageFile is not set: !isset($dbImageFile):

    1. $dbImageFile in your code will always return true when passed to isset() (is set).
    2. $dbImageFile in your code will always return false when passed to !isset() (is not set).