sqlsrv_fetch_array() returns an empty string while sqlsrv_has_rows() returns true

StackOverflow https://stackoverflow.com/questions/23433085

  •  14-07-2023
  •  | 
  •  

Question

While I'm relatively new to php and ajax, I have been sure to research this question thoroughly. I have a php script (Environment.php) that calls my database and populates the navigation panel with all of my environments successfully. Upon clicking an environment (which is a hyperlink to a javascript function), the environment information should populate the div next to the navigation menu through ajax, which calls another php script (GetEnvironment.php). This script has the same database and code as the script before, with a different query.

Now, any sane person would say, "It must be the query." When I print out the query and run it in SSMS, I get the one row that I want. When I check if sqlsrv_has_rows(), it returns true. When I run sqlsrv_fetch_array(), it returns an empty string. When I remove the WHERE clause from my query, it returns the array of environments just fine. "Then it must be the where clause in the query!" You'd think so, but - like I've said, upon printing out the query my php is using, and pasting this query into SSMS, it returns perfectly.

If I change the where clause to "WHERE is_active = 1" or "WHERE e.env_type_id = 1", I get results. If I change the where clause to "WHERE e.id = 102" or "WHERE e.short_desc = 'ABB'", I get the same issue. It's important to note that is_active is a bit and env_type_id is a tinyint, whereas id is an int and short_desc is a varchar.

Keep in mind, all of these queries are double checked in SSMS, in that they DO return results. I have hard-coded the id and it makes no difference, so it shouldn't be $_GET['id'].

Upon running a trace on the database while I make the call, no errors were logged and it seemed to work fine. Upon installing netbeans and trying to debug what the problem might be, I still can't find the root cause.

Environment.php

<!DOCTYPE html>
<html>
    <head>
        <link href='../CSS/Primary.css' rel='stylesheet' type='text/css' />
        <script>
            function loadEnvInfo(id)
            {
                var xmlhttp;
                <!-- The XMLHttpRequest object is used to exchange data with a server behind the scenes. This means that it is possible to update parts of a web page, without reloading the whole page. -->
                if (window.XMLHttpRequest)
                {// code for IE7+, Firefox, Chrome, Opera, Safari
                    xmlhttp=new XMLHttpRequest();
                }
                else
                {// code for IE6, IE5
                    xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
                }

                xmlhttp.onreadystatechange=function()
                                            {
                                                if (xmlhttp.readyState===4 && xmlhttp.status===200)
                                                {
                                                    document.getElementById("envInfo").innerHTML = xmlhttp.responseText;
                                                }
                                            };
                xmlhttp.open("GET","GetEnvironment.php?id="+id,true);
                xmlhttp.send();
            }
    </script>
</head>
<body>
    <div id="pagewidth">
        <div id="header">
            <h2><a href="../index.php">Home</a>
            <a href="Environment.php">Environments</a>
        </div>
        <div id="wrapper">
            <div id="nav">
                <?php
                    $serverName = "myServer\myInstance";
                    $connectionInfo = array( "Database"=>"myDatabase");
                    $conn = sqlsrv_connect( $serverName, $connectionInfo);

                    if ($conn === false)
                    {
                        echo "Connection could not be established.<br />";
                        die( print_r( sqlsrv_errors(), true));
                    }

                    $query = "SELECT e.id,e.long_desc,et.short_desc FROM myTable e INNER JOIN myOtherTable et ON e.env_type_id = et.id";

                    $returnedValue = sqlsrv_query($conn, $query);

                    if ($returnedValue === false)
                    {
                        die(print_r(sqlsrv_errors(),true));
                    }

                    if (sqlsrv_fetch_array($returnedValue) === false)
                    {
                        echo "fetch error";
                    }

                    $envTypes = array();

                    while ( $row = sqlsrv_fetch_array( $returnedValue, SQLSRV_FETCH_ASSOC) )
                    {
                        $env_type = $row['short_desc'];
                        if (array_key_exists($env_type, $envTypes) == false)
                        {
                            $envTypes[$env_type] = array($row['id']=>$row['long_desc']);
                        }

                        $envTypes[$env_type][$row['id']] = $row['long_desc'];
                    }

                    echo "<ul>";

                    foreach($envTypes as $et=>$et_value)
                    {
                        echo "<li>".$et;

                        if(count($et_value) > 0)
                        {
                            echo "<ul>";

                            foreach($et_value as $id=>$long_desc)
                            {
                                echo "<li><a href=\"javascript:loadEnvInfo(".$id.")\">".$long_desc."</a></li>";
                            }

                            echo "</ul>";
                        }

                        echo "</li>";
                    }

                    echo "</ul>";

                    /* Close the connection. */
                    sqlsrv_free_stmt( $returnedValue);
                    sqlsrv_close( $conn);
                ?>
            </div>
            <div id="maincol">
                <div id="envName"><h1>Environment</h1></div>
                <div id="envInfo"><h2>Environment Info</h2></div>
            </div>
        </div>
    </div>
</body>
</html>

GetEnvironment.php

<?php
    $serverName = "myServer\myInstance";
    $connectionInfo = array( "Database"=>"myDatabase");
    $conn = sqlsrv_connect( $serverName, $connectionInfo);

    if ($conn === false)
    {
        echo "Could not connect.\n";
        die( print_r( sqlsrv_errors(), true));
    }

    $query = "SELECT e.[id]
            ,e.[short_desc]
            ,e.[long_desc]
            ,e.[is_active]
            ,et.[short_desc] as env_type
            FROM [myTable] e
            INNER JOIN [myOtherTable] et on e.[env_type_id] = et.[id]
            WHERE e.[id] = ".$_GET['id'];

    // Returns SELECT e.[id] ,e.[short_desc] ,e.[long_desc] ,e.[is_active]
    // ,et.[short_desc] as env_type
    // FROM [myTable] e
    // INNER JOIN [myOtherTable] et on e.[env_type_id] = et.[id]
    // WHERE e.[id] = 102
    echo "Query: ".$query."<br />";

    $returnedValue = sqlsrv_query($conn, $query);

    // $returnedValue returns "Resource id #3"
    if ($returnedValue === false)
    {
        echo "Error in query preparation/execution.<br />";
        die(print_r(sqlsrv_errors(),true));
    }

    if (sqlsrv_fetch_array($returnedValue) === false)
    {
        echo "fetch error";
        die(print_r(sqlsrv_errors(),true));
    }

    // Returns "Has Rows!"
    if (sqlsrv_has_rows($returnedValue))
    {
        echo "Has Rows!";
    }
    else
    {
        echo "No Rows!";
    }

    // Returns "empty string"
    if (sqlsrv_fetch_array($returnedValue) == "")
    {
        echo "empty string";
    }
    else if (sqlsrv_fetch_array($returnedValue) == null)
    {
        echo "null";
    }

    // Does not enter the while loop, skips over it to close the connection
    while ( $row = sqlsrv_fetch_array( $returnedValue, SQLSRV_FETCH_ASSOC ))
    {
        echo "Inside While loop!";
    }

    /* Close the connection. */
    sqlsrv_free_stmt( $returnedValue);
    sqlsrv_close( $conn);
?>
Was it helpful?

Solution 2

Upon removing the if statements (the checks to see if my returnedValue had any value), the script began working. Here is the working php. I will continue to look into the problem to see if I can't find why this script works, and my original script does not. Any other insights into this problem would be very much appreciated.


My proposed answer: By calling sqlsrv_fetch_array($returnedValue) in my if statements, I was removing the array from my returned value. I had already pulled out the information, and was attempting to call that same reference again, which returned to me an empty string, because it no longer contained the array.

Working php:

<?php
    $serverName = "myServer\myInstance";
    $connectionInfo = array( "Database"=>"myDatabase");
    $conn = sqlsrv_connect( $serverName, $connectionInfo);

    if ($conn === false)
    {
         echo "Could not connect.\n";
         die( print_r( sqlsrv_errors(), true));
    }

    $query = "SELECT e.[id]
        ,e.[short_desc]
        ,e.[long_desc]
        ,e.[is_active]
        ,et.[short_desc] as env_type
        FROM [myTabel] e
        INNER JOIN [myOtherTable] et on e.[env_type_id] = et.[id]
        WHERE e.[id] = ".$_GET['id'];

    $returnedValue = sqlsrv_query($conn, $query);

    if( $returnedValue === false)
    {
         echo "Error in query preparation/execution.\n";
         die( print_r( sqlsrv_errors(), true));
    }

    while ( $row = sqlsrv_fetch_array( $returnedValue, SQLSRV_FETCH_ASSOC ))
    {
        echo "Inside loop!";
    }

    /* Free statement and connection resources. */
    sqlsrv_free_stmt($returnedValue);
    sqlsrv_close( $conn);
?>

OTHER TIPS

Typically, it's best to change the way you're doing the query to be considered a bit more "safe".

$query = sprintf(
    "SELECT e.[id]
        ,e.[short_desc]
        ,e.[long_desc]
        ,e.[is_active]
        ,et.[short_desc] as env_type
        FROM [myTable] e
        INNER JOIN [myOtherTable] et on e.[env_type_id] = et.[id]
        WHERE e.[id] = '%s'",
     addslashes($_GET['id']));

This prevents any sort of attack on the database, and adding the single ticks around your id will probably resolve the issue you're experiencing.

As stated in asker's answer, the script fetches one array already in if statement with:

if (sqlsrv_fetch_array($returnedValue) === false)

If you want to check the result of sqlsrv_fetch_array() and also fetch all results successfully, then my suggestion is as below:

$row = sqlsrv_fetch_array( $returnedValue, SQLSRV_FETCH_ASSOC );

if( $row === false ) {
   echo "Error while fetching array.\n";
   die( print_r( sqlsrv_errors(), true));
} else if( $row === null ) {
   echo "No results were found.\n";
} else {
   do {
      echo "Inside loop!";
   } while( $row = sqlsrv_fetch_array( $returnedValue, SQLSRV_FETCH_ASSOC ) );
}

sqlsrv_free_stmt( $returnedValue);
sqlsrv_close( $conn);

Using this way, you can check error and control null result while fetching array at least at the beginning.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top