2

Edit: Just ran into a wrinkle, I just got this working on an iPhone over the weekend and just out of curiosity ran it on two phones at once and it worked. So it ran happily along (as I expected it to the first time) when one phone was an iPhone (iOS 6) and the other was HTC One (Android 4.3). This was however on another person's WIFI. Could my home WIFI be a factor in blocking two devices going to the same location? (The second phone I was using when it didn't work was a Samsung Galaxy Ace 2 (Android 2.3))

So I've got this problem. I am using PhoneGap and coming up with a basic quiz system to muck around with. I've got it working and I'm having a great time. It works essentially through a web console where I can set up a quiz and cycle through questions and with a not so complex series of status updates to an underlying database I use Ajax calls from my mobile to read the status and display a question or wait for the next one.

Basic call is:

$(function checkForQuestion() {
    var postData = "stuff needed in called PHP";
    $.ajax({
        type: "POST",               
        data: postData,             
        url: "my called php",           
        success: function(data){                
        var result = JSON.parse(data);
        if (result == "question") {
            --Display Question
        } else {
            setTimeout(checkForQuestion, 1000);
            return false;
        }
    });         
    return false;
}); 

In my limited experience this seems to be a general use of Ajax with a recursive call back if it needs to wait for a new status.

Now this isn't everything by far, but a taster of what I'm doing. It works extremely well with one mobile device and a web console happily working through quizzes.

When I attempt to add a second mobile (haven't even attempted three yet) what happens is the second mobile just silently fails where it is supposed to be calling this ajax. Now the second mobile can quite happily chug along with this on it's own so it shouldn't be a hardware issue. There are no errors thrown out in the PHP, and with a little logging I can't find anything obviously failing.

At this point I thought, perhaps there is a limit on connections on my web host (I'm just using a shared server web host I'm using to test this out) and there are but that is limited to 20 entry processes with Cloud Linux LVE. However This should not preclude two mobiles calling the same PHP (via wifi) at roughly the same time. It should just run the calls concurrently and one will return slight faster than the other (or that is my understanding).

I thought perhaps this is a lock put on the MySQL database I'm using not allowing multiple users/PHP to query it at roughly the same time, but the consecutive nature of PHP should rule that out and some Googling assures me that calls will be queued.

I'm guessing that what is happening is the two calls come in and without returning any error one silently conflicts with the other causing a fail, but I have no idea hwo to find the fail and fix it.

Any suggestions?

Request for the actual code:

$(function () {
    $(document).on("pagebeforeshow", "#page6", function () {
        document.getElementById("mob_user_name2").innerHTML = window.localStorage.getItem("mob_local_login_name");

        $(function checkForQuestion() {
            //sort out the data to be posted
            var postData = "mob_quizwait_quizcode=" . concat(window.localStorage.getItem("mob_local_quiz_code"), "&mob_quizwait_email=", window.localStorage.getItem("mob_local_login_email"), "&mob_quizwait_password=", window.localStorage.getItem("mob_local_login_password"), "&mob_quizwait_questionid=", window.localStorage.getItem("mob_question_id"));

            $.ajax({
                type: "POST",               
                data: postData,             
                url: "url of php",          
                success: function(data){                
                    var mob_quizwait_data = JSON.parse(data);
                    if (mob_quizwait_data.mob_quizwait_success == "mob quizwait go") {
                        window.localStorage.setItem("mob_question_id", mob_quizwait_data.mob_quizwait_questionid);
                        window.localStorage.setItem("mob_question_score", mob_quizwait_data.mob_quizwait_score);
                        window.localStorage.setItem("mob_question_category", mob_quizwait_data.mob_quizwait_category);
                        window.localStorage.setItem("mob_question_question", mob_quizwait_data.mob_quizwait_question);
                        window.localStorage.setItem("mob_answer1", mob_quizwait_data.mob_quizwait_correct);
                        window.localStorage.setItem("mob_answer2", mob_quizwait_data.mob_quizwait_wrong1);
                        window.localStorage.setItem("mob_answer3", mob_quizwait_data.mob_quizwait_wrong2);
                        window.localStorage.setItem("mob_answer4", mob_quizwait_data.mob_quizwait_wrong3);
                        $.mobile.changePage("#page7", {transition:"slide", changeHash:false});
                    } else if (mob_quizwait_data.mob_quizwait_success == "mob quizwait stay") {
                        setTimeout(checkForQuestion, 1000);
                        return false;
                    } else if (mob_quizwait_data.mob_quizwait_success == "mob quizwait intermission") {
                        document.getElementById("mob_intermission").innerHTML = "Intermission";
                        $.mobile.changePage("#page6", {transition:"none", changeHash:false});
                    } else if (mob_quizwait_data.mob_quizwait_success == "mob quizwait finish") {
                        $.mobile.changePage("#page8", {transition:"slide", changeHash:false});
                    } else {
                        navigator.notification.alert("Status Check Failed. Please Try Again.", function(){}, "Alert", "OK");
                    }
                }       
            });         
            return false;
        }); 
    });
});

And the PHP:

<?PHP

include '../open.php';

//take in POST variables
$quizcode = $link->real_escape_string($_POST["mob_quizwait_quizcode"]);
$email = $link->real_escape_string($_POST["mob_quizwait_email"]);
$password = $link->real_escape_string($_POST["mob_quizwait_password"]);
$questionid1 = $link->real_escape_string($_POST["mob_quizwait_questionid"]);

$quizid = 0;
$status = "X";
$questionid = 0;

$sql = "SELECT QUIZ_ID FROM B_QUIZ WHERE QUIZ_CODE = '$quizcode'";
$res = $link->query($sql);

while ($row = $res->fetch_array()) {
    $quizid = $row['QUIZ_ID'];
}

$sql = "SELECT USER_ID FROM A_USER WHERE USER_EMAIL = '$email' AND USER_PASSWORD = '$password'";
$res = $link->query($sql);

while ($row = $res->fetch_array()) {
    $userid = $row['USER_ID'];
}

$sql = "SELECT QUIZ_STATUS, IFNULL(QUESTION_ID, 0) AS QUESTION_ID FROM B_GAME WHERE QUIZ_ID = $quizid";
$res = $link->query($sql);

while ($row = $res->fetch_array()) {
     $status = $row['QUIZ_STATUS'];
 $questionid = $row['QUESTION_ID'];
}

if ($questionid == $questionid1) {
$questionid = 0;
}

if ($status != "F") {
if ($quizid != 0 && $status != "X") {
    //get details to be written to the profile page
    if ($questionid != 0) {

        $sql = "SELECT SCORE FROM B_PARTICIPANT WHERE USER_ID = $userid AND QUIZ_ID = $quizid";
        $res = $link->query($sql);

        while ($row = $res->fetch_array()) {
            $score = $row['SCORE'];
        }

        $sql = "SELECT b.QUESTION_ID, c.CATEGORY, b.QUESTION, b.CORRECT_ANSWER, b.WRONG_ANSWER_1, b.WRONG_ANSWER_2, b.WRONG_ANSWER_3
                    FROM B_GAME a, B_QUESTION b, D_CATEGORY c
                    WHERE a.QUESTION_ID = b.QUESTION_ID
                    AND b.CATEGORY_ID = c.CATEGORY_ID
                    AND a.QUIZ_ID = $quizid";
        $res = $link->query($sql);

        while ($row = $res->fetch_array()) {
            $questionid = $row['QUESTION_ID'];
            $category = $row['CATEGORY'];
            $question = $row['QUESTION'];
            $correct = $row['CORRECT_ANSWER'];
            $wrong1 = $row['WRONG_ANSWER_1'];
            $wrong2 = $row['WRONG_ANSWER_2'];
            $wrong3 = $row['WRONG_ANSWER_3'];
        }

        if ($status == "R") {
            $arr = array("mob_quizwait_success" => "mob quizwait go", 
                         "mob_quizwait_questionid" => $questionid,
                         "mob_quizwait_score" => $score, 
                         "mob_quizwait_category" => $category, 
                         "mob_quizwait_question" => $question, 
                         "mob_quizwait_correct" => $correct, 
                         "mob_quizwait_wrong1" => $wrong1, 
                         "mob_quizwait_wrong2" => $wrong2,
                         "mob_quizwait_wrong3" => $wrong3);
            echo json_encode($arr);
        } else if ($status == "N") {
            $arr = array("mob_quizwait_success" => "mob quizwait stay");
            echo json_encode($arr);
        } else if ($status == "I") {
            $arr = array("mob_quizwait_success" => "mob quizwait intermission");
            echo json_encode($arr);
        }
    } else {
        $arr = array("mob_quizwait_success" => "mob quizwait stay");
        echo json_encode($arr);
    }
} else {
    $arr = array("mob_quizwait_success" => "mob quizwait failed");
    echo json_encode($arr);
}

} else {
$arr = array("mob_quizwait_success" => "mob quizwait finished");
echo json_encode($arr);
}

include '../close.php';

?>

open.php:

<?PHP

//DATABASE DETAILS//
$DB_ADDRESS = "yeah";
$DB_USER = "not";
$DB_PASS = "gonna";
$DB_NAME = "do it";

//Connect to the MySQL database
$link = new mysqli($DB_ADDRESS, $DB_USER, $DB_PASS, $DB_NAME);  

if (mysqli_connect_errno()) {

        printf("Connect Failed: %s\n", mysqli_connect_error());
        exit();

}                       

?>

close.php:

<?PHP
mysqli_close($link);
?>
ashcanschool
  • 319
  • 3
  • 18
  • Post your real code. All the relevant parts where the error obvious is have been removed. – developerwjk Apr 01 '14 at 22:52
  • Does the call to get the page on the second mobile fail immediately, or simply spin indefinitely? Also are you utilizing PHP sessions anywhere in your application (that is, do you call session_start() anywhere)? – sullivanmatt Apr 02 '14 at 21:21
  • Sorry Just noticed your comment. The issue is that the second call seems to fail silently so I don't know if it is failing or spinning indefinitely. There is no PHP error given. And nothing, it appears, is being returned to the mobile it just sits at the screen that is meant to call to the PHP with no reaction. There is no use of sessions anywhere in this whole setup. For clarity - I think my question is boiling down to how can I better visualize my failure so that I can fix it. – ashcanschool Apr 03 '14 at 12:58
  • Have you ever think about using `or die($link->error);` on any of your queries to actually see if there is a MySQL error since you have none I doubt you will ever see an error from it. You could add to your code some lines for each stage(for example `echo "first query\n";`) so that it will tell you how far it goes before fail if it fails and perhaps output that to a file rather than printing to screen. Also you might be better of using **async AJAX.** – Prix Apr 04 '14 at 13:55
  • What's the URL of this application? I can fiddle and see how those requests are playing out. Also something you'll probably want to do is to override all error handling that your host is doing and output directly to the user while you are debugging this issue. To do that: error_reporting(E_ALL); ini_set('display_errors', 1); – sullivanmatt Apr 04 '14 at 13:59
  • Also Prix makes a completely valid point - your MySQL queries could be dying silently. – sullivanmatt Apr 04 '14 at 14:00
  • As for the SQL failing, that is entirely possible, but it would be curious why the SQL only fails when it is used to query more than once. The system works when only one user is using it, so I would, without testing, look elsewhere for the issue and come back if nothing else worked. I can try to put in or die statements over the weekend though and see if it turns something up. – ashcanschool Apr 04 '14 at 14:47
  • My task over the weekend was to build my own kind of log writing statements to a file and seeing what comes out as mentioned by Prix. – ashcanschool Apr 04 '14 at 14:53
  • As for using async AJAX, I thought by default all AJAX was asynchronous, you can throw in the whole (async: false) to force the AJAX to finish before moving on. Are you suggesting I turn async off? – ashcanschool Apr 04 '14 at 14:55
  • What is the database engine type? If its MyISAM Select query places read lock on the table, as suggested in this [answer](http://stackoverflow.com/a/6415256/2858188), this could be causing the second request to fail, as you said request happen at the same time. Do enable error reporting and check for the errors while making second request. – Engit Apr 11 '14 at 05:24
  • The whole thing is set to innoDB, and while it doesn't lock tables it does implement row locking. This can be worked with using a different type of SQL statement that implements shared locking which might just be it. I'll give this a test. – ashcanschool Apr 11 '14 at 08:26
  • Considering it worked at one location and not at another, it certainly sounds like your WiFi, or provider, may be part of the problem. Can you tell us more about provider and router you are using at home? – Brad Faircloth Apr 11 '14 at 12:43
  • UK - BT Home Hub nothing fancy not sure what other details there are to give. – ashcanschool Apr 11 '14 at 15:11
  • This question appears to be off-topic because it is about a unknown issue with the Web Host provider (from the accepted answer) – bummi May 15 '14 at 12:10
  • Just added my own answer. It was an unknown issue with the Web Host provider. Answer, in this case, was to set up a VPS. – ashcanschool May 15 '14 at 12:17

6 Answers6

2

The silent fail may be because there is a server error when processing the ajax call.

Add an error handler to the ajax call.

$.ajax({
   type: "POST",
   data: postData,
   url: 'url of php',
   success: successFunction(),
   error: function(xhr, status, err) { alert("Ajax request failed"); }
});

You may need to step through PHP code or add additional logging to see the flow of the application.

Kami
  • 19,134
  • 4
  • 51
  • 63
  • Used and no errors are flagged. – ashcanschool Apr 07 '14 at 21:19
  • Glory be! Progress! I see a fail now. I didn't see it at first as it would wait for a bit before failing. I changed the error to: error: function(xhr, status, error) { var err = eval("(" + xhr.responseText + ")"); alert(err.Message);} and this came back "The connection to the server was unsuccessful. (file:///android_asset/www/index.html)" Anybody have an idea what this is telling me? – ashcanschool Apr 07 '14 at 21:50
  • @ashcanschool Seems like the url is incorrect. Are you using the full form eg, `http://www.website.com/script.php` – Kami Apr 08 '14 at 07:26
  • Yep, I had to use the full URL as it wouldn't work otherwise, remember that this works on other phones as well as working on those that silently fail when others are not being used. Looking up the error late last night it seems to indicate that it was timing out. – ashcanschool Apr 08 '14 at 08:45
  • @ashcanschool The timeout simply indicates that it failed to load the resource. The resource in question has an invalid url and hence it fails - it appears to be using a `file:///` prefix which is usually used to load a local file rather than a web page. This is reason why I asked you to check the validity of url. This may be down to device config or some other settings. To ensure maximum compatibility with any devices, use the full url - less chance it will go wrong. – Kami Apr 08 '14 at 09:57
  • The resource in question is an internal file of PhoneGap. It is a valid file in the context of the PhoenGap structure (PhoneGap is a built like a website and this file is the entry point) This internal html file runs all internal aesthetics. Penny just dropped for me here, the error on the failure of the AJAX call is coming back and saying that it can't connect to itself? Does this sound right? – ashcanschool Apr 08 '14 at 14:17
  • @ashcanschool The client end (ajax) is not able to get a response from the requested url. Or more accurately, it waits some time for a response before it returns a timeout error. It may well be a connection problem. – Kami Apr 08 '14 at 14:50
0

Try:

<script>
var st_flag = true;

$(function () {
    $(document).on("pagebeforeshow", "#page6", function () {
        document.getElementById("mob_user_name2").innerHTML = window.localStorage.getItem("mob_local_login_name");      

        $(function checkForQuestion() {    

          if(!st_flag)
          {
             setTimeout(checkForQuestion, 1000); 
          } 

            //sort out the data to be posted
            var postData = "mob_quizwait_quizcode=" . concat(window.localStorage.getItem("mob_local_quiz_code"), "&mob_quizwait_email=", window.localStorage.getItem("mob_local_login_email"), "&mob_quizwait_password=", window.localStorage.getItem("mob_local_login_password"), "&mob_quizwait_questionid=", window.localStorage.getItem("mob_question_id"));

            $.ajax({
                type: "POST",               
                data: postData,             
                url: "url of php",  

               st_flag = false;         

                success: function(data){                
                    var mob_quizwait_data = JSON.parse(data);
                    if (mob_quizwait_data.mob_quizwait_success == "mob quizwait go") {
                        window.localStorage.setItem("mob_question_id", mob_quizwait_data.mob_quizwait_questionid);
                        window.localStorage.setItem("mob_question_score", mob_quizwait_data.mob_quizwait_score);
                        window.localStorage.setItem("mob_question_category", mob_quizwait_data.mob_quizwait_category);
                        window.localStorage.setItem("mob_question_question", mob_quizwait_data.mob_quizwait_question);
                        window.localStorage.setItem("mob_answer1", mob_quizwait_data.mob_quizwait_correct);
                        window.localStorage.setItem("mob_answer2", mob_quizwait_data.mob_quizwait_wrong1);
                        window.localStorage.setItem("mob_answer3", mob_quizwait_data.mob_quizwait_wrong2);
                        window.localStorage.setItem("mob_answer4", mob_quizwait_data.mob_quizwait_wrong3);
                        $.mobile.changePage("#page7", {transition:"slide", changeHash:false});

                        st_flag = true;

                    } else if (mob_quizwait_data.mob_quizwait_success == "mob quizwait stay") {
                        setTimeout(checkForQuestion, 1000); 
                        return false;
                    } else if (mob_quizwait_data.mob_quizwait_success == "mob quizwait intermission") {
                        document.getElementById("mob_intermission").innerHTML = "Intermission";
                        $.mobile.changePage("#page6", {transition:"none", changeHash:false});
                    } else if (mob_quizwait_data.mob_quizwait_success == "mob quizwait finish") {
                        $.mobile.changePage("#page8", {transition:"slide", changeHash:false});
                    } else {
                        navigator.notification.alert("Status Check Failed. Please Try Again.", function(){}, "Alert", "OK");
                    }
                }       
            });         
            return false;
        }); 
    });
});
</script>

Wait for first call to be complete.

Anil R
  • 289
  • 1
  • 6
  • Can you explain how this is doing something different than my setup as is? I have it set up so that it calls the function when the page is loaded and part of that is an AJAX call, if the call comes back with an answer I move on it, if it comes back and says wait then I wait 1 second and then recursively call the AJAX again, it has to finish before calling. It will never step on it's own toes and make two calls which it appears that your code is attempting to stop. Do I have this wrong? – ashcanschool Apr 05 '14 at 18:27
  • OK this has been tried with no effect. – ashcanschool Apr 07 '14 at 09:44
0

Even though your problem is complicated by nature and I've got no reason to come to the conclusion I'm going to say but my bets are on session.auto_start.

As I see you've got no use for session in your code and in your case it might be a problem starting it. Set session.auto_start to false so your code won't use sessions at all and then test your code. It's a long shot but it's the best I've got.

To explain myself, php makes use of files for sessions by default. And it does so by opening the file in exclusive mode. It means if one request is running on the server, the second one with the same session_id will be blocked until the first one realizes it. So each browser can have only one request executed on the server at a time. I know your javascript won't be making the second request before the first one is returned but as I said your problem is complicated and it's the only guess I could come up with and I believe it's worth a test.

So my solution is: make sure you are not using sessions at all.

Mehran
  • 15,593
  • 27
  • 122
  • 221
0

As Kami said, i think there should be some issues in the server side(PHP) only. And lot of time, PHP don't used to show the errors due to the server settings. I would suggest you to check the apache error logs, so that you can get to know if any unshown error is present. To check this, just load the URL which is having the problem and then check the error log usually present in var/log/ folder.

Stranger
  • 10,332
  • 18
  • 78
  • 115
0

I have a strange suggestion after your edit. Wifi hotspot hides real adresses by NAT so from server's point of view both your devices has the same IP address. Server sends the answer to your Wifi spot and it route the packets to real addresses. Sometimes I had package missing but I can't remember the situation when all packets had been lost.

You should request the page from both devices and log the scrpit's work result on the server side. If there was 2 requests and all DB requests worked properly that means that one of your clients didn't get the response. It is probably because of your router, probably NAT

zarkone
  • 1,335
  • 10
  • 16
0

This turned out to be an unknown issue with the Web Host provider. Despite more than a dozen detailed requests for what on their side was blocking things I was always referred to how my own equipment or own code was at fault.

Set myself up a VPS and presto change-o I have a working system with no modifications to the code or the equipment.

TIL I don't like people who cover up their incompetency by blaming others.

ashcanschool
  • 319
  • 3
  • 18