3

Scenario:

I have two PHP scripts to be called simultaneously:

  1. The first script will run several minutes (PHP based file download), depending on downloaded file size. It is placed into <iframe> so it can run separately and does not block the browser.
  2. The second PHP script is supposed to be called in regular intervals to monitor execution of the first script - file progress download. To avoid opening new windows upon script completion, it is called via AJAX.

Problem:

I have placed the long-running PHP Script (download script) into <iframe> so this script can run asynchronously with other monitoring PHP script. However, despite the main script is in <iframe>, when the webpage starts execution, the script starts and blocks execution of the remaining JavaScript code and monitoring script called multiple times via AJAX.

It is important to have the short-running monitoring PHP script called simultaneously with the long-running PHP (download) script, so the short-running (monitoring)script can provide feedback to JavaScript.

Would you be so kind and analyze my code samples please? I have no idea, where is my problem. My code is so simple, that everything should be running well.

  • PHP Version 5.4.12
  • Apache/2.4.4 (Win64) PHP/5.4.12
  • Windows 7 x64
  • 8GB RAM
  • Google Chrome Version 30.0.1599.101 m

Code Samples:

JavaScript code calling both PHP scripts:

<!DOCTYPE html>
<html>
<head>
    <title>Title of the document</title>
</head>

<body onload="callScripts();">


<script type="text/javascript">

    // call both PHP scripts(download and monitoring) in desired order
    callScripts = function()
    {
        // call the monitoring PHP script multiple times in 2 second intervals
        window.setTimeout(function(){startDownloadMonitoring()}, 1000);
        window.setTimeout(function(){startDownloadMonitoring()}, 3000);
        window.setTimeout(function(){startDownloadMonitoring()}, 5000);
        window.setTimeout(function(){startDownloadMonitoring()}, 7000);
        window.setTimeout(function(){startDownloadMonitoring()}, 9000);
    };


    // call monitoring PHP script via AJAX
    function startDownloadMonitoring()
    {
        console.log("Calling startDownloadMonitoring()...");

        var xmlhttp;

        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)
            {
                console.log("Response Received: " + xmlhttp.responseText);
            }
        }
        xmlhttp.open("GET", "PHP/fileDownloadStatus.php", true);
        xmlhttp.send();
    }
</script>

<iframe src="PHP/fileDownload.php"></iframe>

</body>
</html>

PHP Monitoring Script(fileDownloadStatus.php)

<?php

include 'ChromePhp.php';

// start session, update session variable, close session
session_start();
$_SESSION['DownloadProgress']++;
ChromePhp::log('$_SESSION[\'DownloadProgress\'] = ' . $_SESSION['DownloadProgress']);
session_write_close();    

echo "success";
?>

PHP long-running script (fileDownload.php)

<?php
include 'ChromePhp.php';

// disable script expiry
set_time_limit(0);    

// start session if session is not already started
session_start();

// prepare session variables
$_SESSION['DownloadProgress'] = 10;

session_write_close();

for( $count = 0; $count < 60; $count++)
{
    sleep(1);

    print("fileDownload Script was called: ". $count);

    echo "Download script: " . $count;
    ob_flush();
    flush();
}
?>

Screenshot:

PHP Scripts Execution Order - browser waits to finish the script in <iframe> Scripts execution order

Bunkai.Satori
  • 4,698
  • 13
  • 49
  • 77
  • If you can, I would recommend using XHR2. You can now send files via AJAX. http://www.w3.org/TR/XMLHttpRequest2/ – flagoworld Oct 30 '13 at 19:38
  • @teh1, Hi and thanks. To my knowledge, I can only upload files via AJAX, but not download. File Download via AJAX is blocked because of security reason, if I have studied the topic correctly. – Bunkai.Satori Oct 30 '13 at 19:41
  • You can do basically anything you want between two URLs if you set the Access-Control-Allow-Origin header correctly. Have you researched it? – flagoworld Oct 30 '13 at 19:46
  • @teh1, I am studying it now. Quit a lot of text. If you could point me to the right section, please, that would help. There is nothing about file download on that page. I keep reading... – Bunkai.Satori Oct 30 '13 at 19:56
  • What is wrong? it seems that everything worked well, since every return code was 200 which means it went to the server and returned with ok status – Jorge Campos Oct 30 '13 at 20:05
  • @JorgeCampos, as you can see the screenshot: The monitoring PHP script (*fileDownloadStatus.php*) is supposed to run **during the execution** of the download script(*fileDownload.php*) **and not after it** as it is the case now. On the screenshot you see, that the monitoring script(*fileDownloadStatus.php*) is called 5 times **after completion** of *fileDownload.php*. It makes sense, if the AJAX called monitoring scripts monitor the progress of the download script, and I can not make them run simultaneously. – Bunkai.Satori Oct 30 '13 at 20:10
  • @teh1, I found already several sources saying, that I am not able to download files via AJAX. An example [can be this one](http://stackoverflow.com/questions/14682556/why-threre-is-no-way-to-download-file-using-ajax-request). Would you be so kind and provide me with more info, how is it possible to implement file download using XHR2? Are you really sure it is doable? – Bunkai.Satori Oct 30 '13 at 21:24
  • I misunderstood, then. I think you can open the URL to the file in a new window. Once the file starts downloading, the window usually disappears... – flagoworld Oct 30 '13 at 23:28
  • @teh1, I can download a file, but I can not grab download progress information. I would like to take this information via AJAX requests by running small scripts that read session variable. My problem however is, while the download script runs, I can not run any other php script. – Bunkai.Satori Oct 31 '13 at 00:22
  • I don't understand the value in this. Your download's progress is vividly tracked by the browser. There is a reason there is no API for this. – flagoworld Oct 31 '13 at 00:24
  • @teh1, I have a portal where I upload and download files. I have implemented quite nice upload progress bar. I want to use this one for monitoring download too. Lets not question suitability of that solution, please. It is simply my goal, and I look for a solution. – Bunkai.Satori Oct 31 '13 at 00:47
  • @Bunkai.Satori Ok, now I understand and I know what is your problem. let me elaborate as an answer. – Jorge Campos Oct 31 '13 at 02:03

1 Answers1

3

Your problem is as simple as you can imagine. You just don't realize it maybe for a bit lack of knowledge of HTML. So Your code is ok and everything is working as you want but the script that should run at the same time isn't, what is the problem?

<body onload="callScripts();">

This up here is your problem. The onload call only takes place when everything inside the body tag is completely loaded. So, as your iframe is inside the body the html interpreter load everything (including the iframe and its source), then call your callScripts function.

To solve your problem I recommend you to create your iframe inside your script. Would be something as this:

<!DOCTYPE html>
<html>
<head>
    <title>Title of the document</title>

    <!-- You should always define your script in the head tag. best pratice
     defined in W3C -->

<script type="text/javascript">

    callScripts = function (){
         //write your Iframe Here
         document.getElementById("callDownload").innerHTML = '<iframe src="PHP/fileDownload.php"></iframe>'; 
         callScripts_refresh();
    }

    // call both PHP scripts(download and monitoring) in desired order
    callScripts_refresh = function()
    {

        // call the monitoring PHP script multiple times in 2 second intervals
        window.setTimeout(function(){startDownloadMonitoring()}, 1000);
        window.setTimeout(function(){startDownloadMonitoring()}, 3000);
        window.setTimeout(function(){startDownloadMonitoring()}, 5000);
        window.setTimeout(function(){startDownloadMonitoring()}, 7000);
        window.setTimeout(function(){startDownloadMonitoring()}, 9000);
    };


    // call monitoring PHP script via AJAX
    function startDownloadMonitoring()
    {
        console.log("Calling startDownloadMonitoring()...");

        var xmlhttp;

        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)
            {
                console.log("Response Received: " + xmlhttp.responseText);
            }
        }
        xmlhttp.open("GET", "PHP/fileDownloadStatus.php", true);
        xmlhttp.send();
    }
</script>

</head>

<body onload="callScripts();">

<div id="callDownload"></div>

</body>
</html>

Let me know if it work after that

Jorge Campos
  • 22,647
  • 7
  • 56
  • 87
  • finally I see progress with this problem! Thank you very much! Of course you were right, and I really did not realize the problem was in `` I will close this problem and of course mark your answer. However may I have two more questions, please: *Firstly*, does it mean that despite ` – Bunkai.Satori Oct 31 '13 at 10:09
  • 1
    @Bunkai.Satori I've corrected a little bit the code, yesterday when I already turned my pc off I realize that I've putted the iframe creation inside the function that calls itself. Now should be ok. To your new questions: 1 - If an `iframe` is present it is part of the main page and if the iframe take, say, 5 minutes to load, the page will only be considered fully loaded after iframe loads completely. And regards "while its script is running" scripts at the point of loading page will only run if you call it directly but this way you can be bit messy cause you could refer to something the wasnt – Jorge Campos Oct 31 '13 at 11:43
  • 1
    ...loaded completely. So be carefull with this. 2 - I've learned by reading many many times the W3C. As this especific matters you can see it here: http://www.w3schools.com/jsref/event_onload.asp – Jorge Campos Oct 31 '13 at 11:46
  • thank you for improvement of your script, and your valuable advice. I will study the link you gave me properly. So `` basically means, that whatever is in `fileDownload.php`, it is considered as loaded, when the script winishes its work. I believe this was the key information that I was missing. An example: if there is infinite loop in `fileDownload.php`, the – Bunkai.Satori Oct 31 '13 at 12:17
  • Glad to help. And yes, if was an infinite loop inside `fileDownload.php` the page would never fire the onload event. – Jorge Campos Oct 31 '13 at 12:27