Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get bytes transferred using PHP5 for POST request

Note I am new to PHP, Apache and programming for servers so more thorough explanations will be appreciated.


Context

I created - in javascript - a progress bar to display when a file is uploaded. Current I have the progress bar update at a set frame-rate (to see if it works).

Clearly to make this an accurate progress bar, everything should in relation to the number of bytes transferred in comparison to the total number of bytes.

Question

using PHP5 how can I get information regarding the number of bytes transferred in relation to the total number of bytes of the file, such that I can pass that to a JS function updateProgress(bytesSoFar, totalBytes) to update my progress bar? Please verbosely walk me through the modifications needed to the code below to get this to work. I have seen xhr examples, but they are not thoroughly accessible.

I have just set up LocalHost and am using W3Schools' PHP File Upload tutorial. To get the simulated ''upload'' to work, I changed the local permissions as suggested in this S.O. post. I don't necessarily need to read the file, I just want to know many bytes have been transferred.


Code

Currently I have two files:

  • index.php

  • upload.php

index.php

<!DOCTYPE html>
<html>
<body>

<form action="upload.php" method="post" enctype="multipart/form-data">
    Select image to upload:
    <input type="file" name="fileToUpload" id="fileToUpload">
    <input type="submit" value="Upload Image" name="submit">
</form>

</body>
</html>

upload.php

<?php
$target_dir = "uploads/";
$target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);
$uploadOk = 1;
$imageFileType = pathinfo($target_file,PATHINFO_EXTENSION);
// Check if image file is a actual image or fake image
if(isset($_POST["submit"])) {
    $check = getimagesize($_FILES["fileToUpload"]["tmp_name"]);
    if($check !== false) {
        echo "File is an image - " . $check["mime"] . ".";
        $uploadOk = 1;
    } else {
        echo "File is not an image.";
        $uploadOk = 0;
    }
}
// Check if file already exists
if (file_exists($target_file)) {
    echo "Sorry, file already exists.";
    $uploadOk = 0;
}
// Check file size
if ($_FILES["fileToUpload"]["size"] > 500000) {
    echo "Sorry, your file is too large.";
    $uploadOk = 0;
}
// Allow certain file formats
if($imageFileType != "jpg" && $imageFileType != "png" && $imageFileType != "jpeg"
&& $imageFileType != "gif" ) {
    echo "Sorry, only JPG, JPEG, PNG & GIF files are allowed.";
    $uploadOk = 0;
}
// Check if $uploadOk is set to 0 by an error
if ($uploadOk == 0) {
    echo "Sorry, your file was not uploaded.";
// if everything is ok, try to upload file
} else {
    if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
        echo "The file ". basename( $_FILES["fileToUpload"]["name"]). " has been uploaded.";
    } else {
        echo "Sorry, there was an error uploading your file.";
    }
}
?>

Update

I have found this code:

test.php

<?php
if ($_SERVER["REQUEST_METHOD"] == "POST" && !empty($_FILES["userfile"])) {



  // move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)
move_uploaded_file($_FILES["userfile"]["tmp_name"], "uploads/" . $_FILES["userfile"]["name"]);
}
?>
<html>
<head>
  <title>File Upload Progress Bar</title>
  <style type="text/css">
    #bar_blank {
    border: solid 1px #000;
    height: 20px;
    width: 300px;
    }

    #bar_color {
    background-color: #006666;
    height: 20px;
    width: 0px;
    }

    #bar_blank, #hidden_iframe {
    display: none;
    }
  </style>
</head>
<body>

  <div id="bar_blank">
    <div id="bar_color"></div>
  </div>
  <div id="status"></div>

  <form action="<?php echo $_SERVER["PHP_SELF"]; ?>" method="POST" id="myForm" enctype="multipart/form-data" target="hidden_iframe">
    <input type="hidden" value="myForm" name="<?php echo ini_get("session.upload_progress.name"); ?>">
    <input type="file" name="userfile"><br>
    <input type="submit" value="Start Upload">
  </form>

  <script type="text/javascript">
    function toggleBarVisibility() {
      var e = document.getElementById("bar_blank");
      e.style.display = (e.style.display == "block") ? "none" : "block";
    }

    function createRequestObject() {
      var http;
      if (navigator.appName == "Microsoft Internet Explorer") {
        http = new ActiveXObject("Microsoft.XMLHTTP");
      }
      else {
        http = new XMLHttpRequest();
      }
      return http;
    }

    function sendRequest() {
      var http = createRequestObject();
      http.open("GET", "progress.php");
      http.onreadystatechange = function () { handleResponse(http); };
      http.send(null);
    }

    function handleResponse(http) {
      var response;
      if (http.readyState == 4) {
        response = http.responseText;

        document.getElementById("bar_color").style.width = response + "%";
        document.getElementById("status").innerHTML = response + "%";

        if (response < 100) {
          setTimeout("sendRequest()", 1000);
        }
        else {
          toggleBarVisibility();
          document.getElementById("status").innerHTML = "Done.";
        }
      }
    }

    function startUpload() {
      toggleBarVisibility();
      setTimeout("sendRequest()", 1000);
    }

    (function () {
      document.getElementById("myForm").onsubmit = startUpload;
    })();
  </script>
</body>
</html>

progress.php

session_start();

$key = ini_get("session.upload_progress.prefix") . "myForm";
if (!empty($_SESSION[$key])) {
  $current = $_SESSION[$key]["bytes_processed"];
  $total = $_SESSION[$key]["content_length"];
  echo $current < $total ? ceil($current / $total * 100) : 100;

  $message = ceil($current / $total * 100) : 100;

  $message = "$message"
  echo "<script type='text/javascript'>alert('$message');</script>";
}
else {
  echo 100;
}
?>

Which, like my previous code, transfers the file. However, this doesn't show the bytes until the end (even though it should alert for that), also it opens a new window with the "Done." statement in the previous window.

like image 903
SumNeuron Avatar asked Feb 26 '17 09:02

SumNeuron


2 Answers

You can check out this Php File Upload Progress Bar that may help you get started in case you insist on using Php to display progress. This uses the PECL extension APC to get uploaded file progress details. It is possible to calculate the number of bytes received by the server using the response of apc_fetch() as per the first link.

Another interesting Track Upload Progress tutorial that uses Php's native Session Upload Progress feature.

Lastly, if you are a little open to using Javascript (or a JS library), that would be ideal. An easy to use, easy to setup, well known and a maintained library that I know of is FineUploader

like image 61
Niket Pathak Avatar answered Sep 18 '22 15:09

Niket Pathak


You can use the Session Upload Progress feature. It's native but require some php.ini configuration.

Please, take a look at the PHP manual.

UPDATE 1

Note, you don't need to change your upload.php. You can create a new php file (ex. progress.php) and make requests to them to check the upload progress with your JS.

progress.php

<?php
$upload_id = $_GET['upload_id];
print json_encode($_SESSION['upload_progress_'.$upload_id]);

Then your JS will make a GET request to progress.php?upload_id=YourIdValue and you will receive a JSON with all progress information.

like image 33
Pedro Faria Avatar answered Sep 17 '22 15:09

Pedro Faria