2

I have been working on exceptions thrown by php - mysqli & created this snippet below that tries to check a few times to see if a temp glitch has caused the database to fail. if so, it tries to recover. If it cannot then it quits/ ends.

Now while the logic is fine, I cannot find out why the echo statements do not occur at regular intervals as they should. Only towards the end (depending upon how the exception is thrown in the findMail() function), the output is spewed & correctly so. The throw new exception line can be changed to fail at all times or to pass the last time around. It is set to pass the last time round in the snippet. Would be great if someone can point to me why the echo is not displaying the output as it should at intervals.

Further I am not sure if this is a good or a bad idea in production. Any feedback on this is very welcome. Thanks to all.

The code Snippet:

<?php
$host        = 'localhost';
$user        = 'root';
$password    = '';
$database    = 'test';

// OPEN A CONNECTION TO THE DATA BASE SERVER AND SELECT THE DB

try
{
    $con = new mysqli($host,$user,$password,$database);
    if($con->connect_error)
    {
        throw new Exception("Goof Up");
    }   
    mysqli_set_charset($con, "utf8"); 
}
catch(Exception $e)
{
    echo $e->getMessage();
    exit;
}

// All well so far 

$cnt = 0;
if(findMail($con,$cnt)) echo "<br> Hurray !!";

function findMail($con,$cnt)
{
    try
    {   
        echo $cnt++."<br>";
        $query = "SELECT name, email from users";
        $stmt=$con->prepare($query);
        if($cnt < 3 ) throw new exception($cnt);
        if($stmt->execute())    
        {   
            $stmt->bind_result($name, $email);
            while ($stmt->fetch())
                {
                    $email = htmlspecialchars($email);
                    $name = htmlspecialchars($name);
                    echo $name.' ---- '.$email.'<br>'; 
                }       
        }
    }
    catch(Exception $e)
    {
        $cnt = (int)($e->getMessage());
//      echo $cnt;
        if($cnt === 4) { echo "Ending"; exit();} 
        sleep(5);
        findMail($con,$cnt);
    }   
    return true;
}
?>
cybersoft
  • 1,453
  • 13
  • 31
Ajoo
  • 63
  • 1
  • 9
  • can you please add the output to your code snippet? – Ole K Jun 17 '15 at 10:47
  • Sure the output is 0 1 2 and I get the names --- emails and "Hurray !" . The output is correct and as expected. Just that the 0,1,2 and so on should be echoed at the 5 sec intervals but they are not. The entire output happens at the end of the 20 seconds interval or depends upon the value of
    if($cnt < 3 ) throw new exception($cnt); 
    – Ajoo Jun 17 '15 at 11:24
  • how about using the flush() / ob_flush() - what is the reason of doing: `if($cnt < 3 ) throw new exception($cnt);`? – Ole K Jun 17 '15 at 11:39
  • ya I tried the function flush() but that did not work either. The reason for
     if ($cnt<3) throw new exception 
    is to simulate a failure 3 times and then finally let the query succed the 4th time. Just to check that the code would handle unexpected queries as desired which is to not terminate the program immediately but try a few times ($cnt) before exiting.
    – Ajoo Jun 17 '15 at 11:52
  • Here's a link to the file that I modified as per your suggestions. http://codepen.io/ajoo/pen/OVjdqj.html . Please note that errScript.php just contains one line of code. '
     if(findMail($con,$cnt)) echo "Hurray !!" 
    '
    – Ajoo Jun 17 '15 at 11:53
  • Kindly someone take a look at the file at the link in the comment above and find the flaw in it. This one uses javascript for adding a delay and retrying the findMail() for a specified number of tries. This is as suggested by Ole K and is a nice idea. Possibly I have made some mistakes due to limited knowledge of JQuery and Ajax. Thanks – Ajoo Jun 18 '15 at 08:38
  • your php script working with ajax: http://pastebin.com/uJvhLm7P and the html document: http://pastebin.com/SqVYe301 - check the console.log output on your browser – Ole K Jun 18 '15 at 09:32
  • Is it possible to combine the above two in a single file? i.e. ajax: [link](pastebin.com/uJvhLm7P) and html document: [link](pastebin.com/SqVYe301). I have tried but it does not function as it does with the 2 seperate files. ( I changed the url : urlname names accordingly where it was required.) – Ajoo Jun 19 '15 at 07:23

2 Answers2

1

It must have something to do with browser rendering while using ob_start and ob_flush under certain conditions.

I noticed when i set php header("Content-Encoding: none") to disable gzip compression:

UPDATE - added an example

<?php 
header("Content-Encoding: none"); 

ob_end_clean();
ob_start(); 

for($i=0;$i<5;$i++) 
{ 
    echo 'No. '.$i."<br>";
    ob_flush();
    flush();
    sleep(2);
}
?>

it flushes properly. Check out more details on the below links

PHP Streaming/Output Buffering no longer working

For php flush - how to disable gzip for specific file?

Community
  • 1
  • 1
Ole K
  • 754
  • 1
  • 9
  • 32
  • Hi, I have gone through & tried out these options in the various snippets I created but without success. The sleep funtion for some unknown reason puts the echo till the very end of the delay. The output occurs all at once towards the end. Here is a small snippet if someone can find how this can be made to work as intended, then this would be solved `"; ob_flush(); flush(); sleep(2); } ?>` – Ajoo Jun 18 '15 at 08:04
  • @Ajoo try to add `ob_end_clean();` as shown in the updated answer – Ole K Jun 18 '15 at 08:43
  • @ Ole K -- Wow ! Working Great !! Finally sleep & echo are friends. I am also very interested in the original modification by you to do this via JQuery and Ajax. ( I believe using sleep is not a great idea. ). Please look at the last comment above this block where I have posted a link to a file I created to the best of my ability to implement the Jquery and Ajax version of this one. Please find what the error is there too. :-) – Ajoo Jun 18 '15 at 09:30
0

Using this PHP script with sleep(X) can cause the user to wait until its complete (successfully or not).

I recommend to call the script through AJAX (E.g. jQuery.ajax([...])), so the frontend is not blocked.

UPDATED - Example of using ajax instead

File: test.php

<?php
// verify if this is an ajax request (if, so exit the script before out)
if(isset($_GET['ajax'])) {

    $host        = 'localhost';
    $user        = 'root';
    $password    = '';
    $database    = 'test';

    // return result being parsed by JS through json_encode
    $result = array('data' => null, "error" => false);

   /**
    * function to return name and emails as array list
    */
   function findMail($con)
   {
        $data = null;
        $query = "SELECT username, uid from tbl_user";
        $stmt=$con->prepare($query);
        if($stmt->execute())
        {      
                $data = [];
                $stmt->bind_result($name, $email);
                while ($stmt->fetch())
                {
                        $email = htmlspecialchars($email);
                        $name = htmlspecialchars($name);
                        $data[] = array('name' => $name, 'email' => $email);
                }
        }
        return $data;
    }

    try
    {
        $con = new mysqli($host,$user,$password,$database);
        if($con->connect_error)
        {
                throw new Exception("Goof Up");
        }      
        mysqli_set_charset($con, "utf8");

        $result['data'] = findMail($con);
    }
    catch(Exception $e){
        $result['error'] = true;
    }

    echo json_encode($result);
    exit;
}
?>
<!DOCTYPE>
<head>
<title>TEST 1</title>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
    <script type="text/javascript">

        $(function(){
                var retryCounter = 0;
                var repeatInterval = 3000;
                var repeatCall = function(){
                        if(retryCounter >= 3) {
                                console.log('max retries reached');
                                return;
                        }
                        console.log('Calling...');

                        $.ajax({
                                url: "test.php?ajax=1",
                                dataType: "json"
                        })
                        .done(function( result, textStatus, xhr ) {
                            // data = the json encoded result from errScript.php
                                console.log("received data from errScript.php");

                                if(!result) {
                                        console.log('STOPPED due to invalid/empty data');
                                        return;
                                }

                                // on error, retry and increase counter
                                if(result.error)
                                {
                                        setTimeout(repeatCall, repeatInterval);
                                        retryCounter++;
                                        return;
                                }

                                $.each(result.data, function(k, v){
                                        document.write(v.name + " --- " + v.email + "<br />");
                                });
                   }).fail(function(xhr, textStatus, err) { console.log('error'); });
                };

                setTimeout(function() { repeatCall(); }, repeatInterval);      
        });

   </script>

</head>
<body>
        <h1> TEST 1 </h1>
</body>  
</html>
Ole K
  • 754
  • 1
  • 9
  • 32
  • HI ! From what I gather the changes you made do not make use of the try catch block at all to catch the exceptions. Is that so ? Also I have seldom if ever worked with Ajax and so I am finding it a bit difficult to try this out. But I think I need to remove the try catch block altogether from my findMail function. I am trying to make changes to try this out. Thanks – Ajoo Jun 17 '15 at 10:26
  • Hi Ole K ! So I have tried to do something with your suggestions. I have created a file that does not work but I am unable to post it here as it says that it's too long for comments . Please someone guide me how I may post my code here. Thanks. – Ajoo Jun 17 '15 at 11:19
  • @Ajoo I have updated the example to have both in one file - But i do not recommed this - Good (PHP) programers will always split "graphical" part from code part. HINT: Search for Smarty Template Engine – Ole K Jun 19 '15 at 07:41
  • I know it's not considered right here according to the rules and while I apologize to the admin , I have gotta say thank you for the help extended !! – Ajoo Jun 19 '15 at 18:19