1

I need to show website visitor that something went wrong should him making queries to my database fails technically. Want to get the php code to echo "Sorry! Something went wrong!" if for some reason data fetching failed.

Following are some ways I am trying to accomplish this. 3 samples. They result in neverending loops thus crashing my browser. (NOTE the IFs on each sample. That is where the 3 samples differ).

I ranked them according to favourite .... How to fix this to bare minimum to achieve my purpose ? Would appreciate codes samples. I know how to achieve this with mysqli_stmt_get_result() but need to learn with the mysqli_stmt_bind_result() in procedural style programming. Not into oop yet. Nor pdo.

1.

<?php

//LOOPS NEVERENDING

$server = 'localhost';
$user = 'root';
$password = '';
$database = 'brute';

$conn = mysqli_connect("$server","$user","$password","$database");

$keywords = 'keyword';

$query = 'SELECT id,domain from links WHERE keywords = ?';
$stmt = mysqli_stmt_init($conn);
if(mysqli_stmt_prepare($stmt,$query))
{
    mysqli_stmt_bind_param($stmt,'s',$keywords);
    if(mysqli_stmt_execute($stmt))
    {
        while($result = mysqli_stmt_bind_result($stmt,$id,$domain))
        {
            mysqli_stmt_fetch($stmt);
            
            echo 'Id: ' .$id; echo '<br>';
            echo 'Domain: ' .$domain; echo '<br>';
            
            if(!$result)
            {
                echo 'Sorry! Something went wrong. Try again later.';
            }
        }
    }
    mysqli_stmt_close($stmt);
    mysqli_close($conn);
}

?>
<?php

//LOOPS NEVERENDING

$server = 'localhost';
$user = 'root';
$password = '';
$database = 'brute';

$conn = mysqli_connect("$server","$user","$password","$database");

$keywords = 'keyword';

$query = 'SELECT id,domain from links WHERE keywords = ?';
$stmt = mysqli_stmt_init($conn);
if(mysqli_stmt_prepare($stmt,$query))
{
    mysqli_stmt_bind_param($stmt,'s',$keywords);
    mysqli_stmt_execute($stmt);
    
    while(mysqli_stmt_bind_result($stmt,$id,$domain))
    {
        if(mysqli_stmt_fetch($stmt)) //If 'Rows Fetching' were successful.
        {
            echo 'Id: ' .$id; echo '<br>';
            echo 'Domain: ' .$domain; echo '<br>';
        }
        else //If 'Rows Fetching' failed.
        {
            echo 'Sorry! Something went wrong. Try again later.';
        }
    }       
    mysqli_stmt_close($stmt);
    mysqli_close($conn);
}

?>
<?php

//LOOPS NEVERENDING

$server = 'localhost';
$user = 'root';
$password = '';
$database = 'brute';

$conn = mysqli_connect("$server","$user","$password","$database");

$keywords = 'keyword';

$query = 'SELECT id,domain from links WHERE keywords = ?';
$stmt = mysqli_stmt_init($conn);
if(mysqli_stmt_prepare($stmt,$query))
{
    mysqli_stmt_bind_param($stmt,'s',$keywords);
    if(mysqli_stmt_execute($stmt)) //If 'Query Execution' was successful.
    {
        while(mysqli_stmt_bind_result($stmt,$id,$domain))
        {
            mysqli_stmt_fetch($stmt);
            
            echo 'Id: ' .$id; echo '<br>';
            echo 'Domain: ' .$domain; echo '<br>';
        }       
    }
    else //If 'Query Execution' failed.
    {
        echo 'Sorry! Something went wrong. Try again later.';
    }
    mysqli_stmt_close($stmt);
    mysqli_close($conn);
}

?>

  • Why so much code? – Dharman Apr 25 '21 at 10:56
  • You're not supposed to bind in a loop. You should bind once and fetch in a loop. – El_Vanja Apr 25 '21 at 10:56
  • 1
    FYI If you are only starting to learn PHP then you should learn PDO instead of mysqli. PDO is much easier and more suitable for beginners. Start here https://phpdelusions.net/pdo & https://websitebeaver.com/php-pdo-prepared-statements-to-prevent-sql-injection Learning mysqli first is going to be a terrible experience for you. – Dharman Apr 25 '21 at 12:06
  • @Dharman, Been sugegsted pdodelusions.com before many times about 5 years ago but pdo does my head-in and that site. Will try your other link websitebeaver.com to see if that makes it easier to learn. – studentprogrammer2020 Apr 26 '21 at 09:56
  • @El_Vanja, Thanks for making it clear that I need to mysqli_stmt_bind_result() only once and not once on each WHILE loop. I thought, since on each loop a new row would be fetched then the new row's data must be bound each time. Now from your hint, I understand that, when I bind once, php understands which $vars (mysqli_stmt_bind_result($stmt,$var)) represent which mysql tbl cols and so don't need to teach it on each and every loop. – studentprogrammer2020 Apr 26 '21 at 09:59

2 Answers2

0

Basically, all of the approaches are wrong. If the query fails then there will be an error triggered automatically by PHP as long as you have error reporting enabled, see How to get the error message in MySQLi?. You should not be checking for it manually. Your code is way longer than it needs to be. Consider how it should be done properly:

<?php

$server = 'localhost';
$user = 'root';
$password = '';
$database = 'brute';

// enable error reporting
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$conn = mysqli_connect($server, $user, $password, $database);
mysqli_set_charset($conn, 'utf8mb4');

$keywords = 'keyword';

$query = 'SELECT id,domain from links WHERE keywords = ?';
$stmt = mysqli_prepare($conn, $query);
mysqli_stmt_bind_param($stmt, 's', $keywords);
mysqli_stmt_execute($stmt);
mysqli_stmt_bind_result($stmt, $id, $domain);

// This loop will keep on going as long as fetch() returns true.
// It will return false when it reaches the end
while (mysqli_stmt_fetch($stmt)) {
    echo 'Id: ' .$id;
    echo '<br>';
    echo 'Domain: ' .$domain;
    echo '<br>';
}

When you enable mysqli error reporting, your code becomes much simpler. There's no need for any special message to the user. When a query fails then an error will be triggered just like any other PHP error and handled the same way. If you want you can then customize the error page, but that is a completely separate topic.

The loop on mysqli_stmt_fetch() is used to fetch the data from the server. The data will be read row by row, and when there are no more rows mysqli_stmt_fetch() will return false.

mysqli_stmt_bind_result() needs to be called only once. Its purpose is to provide variable placeholders into which the data will be populated.

Dharman
  • 30,962
  • 25
  • 85
  • 135
  • ,Thanks for your sample. I know how to use mysqli_stmt_get_result(). Got tired of it. mysqli_stmt_bind_result() seems less code so looking into it again as I have forgotten a lot on it. – studentprogrammer2020 Apr 25 '21 at 11:07
  • `mysqli_stmt_bind_result()` is definitely more code than `get_result` especially when you have a lot of columns. It is a matter of preference, but you can do much more with `get_result` – Dharman Apr 25 '21 at 11:08
  • So, I should only use the WHILE loop on the mysqli_stmt_fetch() line ? Just like we do on the mysqli_stmt_get_result() ? – studentprogrammer2020 Apr 25 '21 at 11:09
  • 1
    Downvoted because I think : 1) You are not answering to the question "how to say something went wrong ?" 2) You are telling to somebody who learn the language to simply ignore all error checking. (and not only errors) 3) OP "need to learn with the mysqli_stmt_bind_result()" so your suggestion is off topic and you dont explain the neverending loops. (why not using PDO at least ?) 4) Just my opinion but "Procedural style is a relic from old PHP days." is not true. – fdglefevre Apr 25 '21 at 22:56
  • @fdglefevre 1. I am answering exactly that point. When something goes wrong PHP throws an error. 2. On the contrary, I am telling them to enable full error reporting. Did you miss the line `mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);`? 3. my example uses `mysqli_stmt_bind_result`, so what do you mean? 4. It might be an opinion, but it does not make it false. The procedural style was added to help people in the transition from PHP 4. – Dharman Apr 25 '21 at 23:29
  • @fdglefevre I took your comment under consideration and explained it better. – Dharman Apr 25 '21 at 23:33
  • If you suggest to enable error reporting globally, can you give some doc or links on how to do it ? Of course when you are on your development environment you should enable all errors reporting available. It's also important to check what are values returned by functions. Furthermore for peoples learning. What if you want to continue your script if an error occurs or want to display a friendly message to your users if something bad happen ? Have you a good solution to support this ? (do you manage specific cases like with exceptions handlers in most frameworks ? how ?) – fdglefevre Apr 26 '21 at 00:24
  • @fdglefevre See the link in my answer. Error reporting must be enabled in full always. In production however these errors must be logged to a file instead of being displayed. It's almost never a good idea to check return values. If you want to recover from an error then catch it just like any PHP error. I don't see what's special here. – Dharman Apr 26 '21 at 00:34
  • I'm okay with most of the pointed answer except I think it doesn't cover something that seems important to me. When the OP says "need to show website visitor that something went wrong" I understand that we need "personalized messages" (it is subject to interpretation of course) You can do that by catching globally exceptions but messages will be less specific to the situation were error occured. Take these 2 errors :"Database disconnected" or "We can't save your profile." For that you need to try/catch as fast as possible, not globally. (also globally is required for unexpected errors) – fdglefevre Apr 26 '21 at 00:55
  • @fdglefevre,I have tried many times to learn about the Error Handlings (Exceptions, Try, Block, Catchall) but the php manual code samples seem too deep for a beginner and always put me off and so I stick to the likes of w3schools.com, tutorialrepublic.com, tutorialspoint.com, etc. but sometimes these sites miss things out. Hence, I would appreciate any very simple basic code samples from you on Error Handlings (Exceptions, Try, Block, Catchall). A very basic in procedural style. You're welcome to add your codes on my original code. That should be enough for me to begin by. Thanks! – studentprogrammer2020 Apr 26 '21 at 10:59
  • @Dharman, Do you mind showing a code sample where my original php code after amending, shows a user friendly error message to website visitor and logs the error (technical bit) for the Admin ? I need to learn how to log errors for the Admin to sneek-peek. They say, need to log errors outside the public_html folder so it's not accessible to malicious visitors, like hackers, so they don't access the log. I don't know how to do this logging outside the public_html folder. – studentprogrammer2020 Apr 26 '21 at 11:09
  • @studentprogrammer2020 See the link I provided. You seem to misunderstand how error messages are shown to the user. When there is an error then the user will see error 500 page. You can customize that page to be more user friendly. **Error messages have nothing to do with database logic!!!** – Dharman Apr 26 '21 at 11:41
  • @studentprogrammer2020 See the first User Contributed Note on this page https://www.php.net/manual/en/function.set-error-handler.php He try to catch all errors/exception and report them in a log file. Just make sur your are not displaying a technical error message to your users in production. It can be a security issue. – fdglefevre Apr 26 '21 at 14:45
-2

Their is a mistake in your code that make your code loop forever. In such cases, a while loop in your code is one of the most common cause of this kind of problem.

When you are using any function you should consider to read the documentation of this function and check what kind of errors and what kind of results (returns) it can give you. Functions can throw errors, warning, Exceptions, or return error codes. Also dont underestimate examples on the PHP documentation of each function. It give you a good idea of how things works.

When you are calling a function it's generally good to check the result returned. I will not rewrite all the documentation here but here is an example for mysqli_stmt_bind_result :

https://www.php.net/manual/en/mysqli-stmt.bind-result.php

This part of the procedural example is important for you :

/* bind variables to prepared statement */
mysqli_stmt_bind_result($stmt, $col1, $col2);

/* fetch values */
while (mysqli_stmt_fetch($stmt)) {
    printf("%s %s\n", $col1, $col2);
}

Here you can see how mysqli_stmt_bind_result and mysqli_stmt_fetch can be used together to loop through your results. But this is not perfect for error checking. The documentation of mysqli_stmt_bind_result says in section Return values :

Returns true on success or false on failure.

So in case of failure of this function you can check for errors this way :

if (!mysqli_stmt_bind_result($stmt, $id, $domain)) {
    die("mysqli_stmt_bind_result has failed !"); // of course you can use something more sophisticated than dying...
}

In case of success, and the source of your infinite loop is here, it returns true. So doing while(mysqli_stmt_bind_result($stmt, $id, $domain)) is a mistake, first because you dont have to loop on this function (it's a job for mysqli_stmt_fetch), secondly because mysqli_stmt_bind_result will ever returns true in your case and your while loop will never end.

For mysqli_stmt_fetch now, there is a subtle difference. Check the return values : https://www.php.net/manual/en/mysqli-stmt.fetch.php

Return Value Description
true Success. Data has been fetched
false Error occurred
null No more rows/data exists or data truncation occurred

Here you have to check for 3 different values and dont forget that null and false can both be evaluated as falsy if you dont take care.

This doesnt allow to display an error :

while (mysqli_stmt_fetch($stmt)) { // is result false or null ? we dont know
    printf ("%s (%s)\n", $id, $domain);
}

This is more complete :

$fetchResult = null;
while ($fetchResult = mysqli_stmt_fetch($stmt)) {
    printf ("%s (%s)\n", $id, $domain);
}
/* dont forget to use 3 equal signs to also compare variable type */
/* null == false   values are considered the same */
/* null === false   this also compare variable types, here types are not the same */
if ($fetchResult === false) {
    die("mysqli_stmt_fetch failed !");
}

Now you are free to read the documentation of all called functions to do your errors checks.

Also note that another error management (less verbose and error prone) is possible using Exceptions objects like explained by Dharman answer

fdglefevre
  • 672
  • 4
  • 15
  • Thank you very much! If I can remember what you just said then I should immediately start becoming a better programmer! You explained all the necessary basic bits about php built-in functions in one single post that I never managed to learn at other forums in 5 years! – studentprogrammer2020 Apr 26 '21 at 10:17