Archive

Posts Tagged ‘array’

Simple dynamic multiple file uploader using Javascript and PHP

September 27th, 2012 No comments

In previous post Handling array with Javascript and PHP, We have dealt with the multiple inputs with Javascript and PHP, so can we do the same to file inputs?

The answer is YES, but there few things to note, so there is an example of how to build a simple dynamic multiple images uploader which show the uploaded link. There are a number of options of the fancy JQuery/Javascript uploader, but it’s always good to know from the basic.

HTML File Input Field

<div id="image_container">
  <input name="image[]" type="file" onchange="addImageBox(this, 0)">
  <span id="image_hint[0]"></span>
</div>

Here we use onChange to call a Javascript function addImageBox every time users select a file. span with id image_hint is used to display the upload file

Javascript

function addImageBox(fileBox, id){
  var container = document.getElementById('image_container');
  var hintBox = document.getElementById('image_hint['+id+']');
 
  var filename = fileBox.value;
  filename = filename.replace(/\s/g, '_');
  hintBox.innerHTML = '&lt;img src="/images/' + filename + '"&gt;';
 
  container.appendChild(document.createElement('br'));
 
  var newfileBox = container.appendChild(document.createElement("input"));
  newfileBox.type = 'file';
  newfileBox.name = 'image[]';
  newfileBox.setAttribute('onchange','addImageBox(this, ' + (id+1) + ');');
 
  var newHintBox = document.createElement('span');
  newHintBox.id = 'articles_image_hint[' + (id+1) + ']';
  container.appendChild(newHintBox);
 
}

addImageBox takes inputs of the current file input box and its index, and dynamically update the image_hint and create another file input box, following by appends them at the end of the div wrapper

PHP Inputs Handler

So, the files will be passed as a array and $_FILES[‘image’] will have the following structure:
Array ( [name] => Array ( [0] => image1.jpg [1] => image2.jpg [2] => )
[type] => Array ( [0] => image/jpeg [1] => image/jpeg [2] => )
[tmp_name] => Array ( [0] => /home/9-web/9b/6c/mysite.com/tmp/phpf1FRWY [1] => /home/9-web/9b/6c/mysite.com/tmp/phpx7se2v [2] => )
[error] => Array ( [0] => 0 [1] => 0 [2] => 4 )
[size] => Array ( [0] => 32169 [1] => 10463 [2] => 0 ) )
each attributes of the file inputs is an array, then we simply deal with the attributes as array form using PHP as:

if(isset($_FILES['image']) && is_array($_FILES['image'])){
  foreach($_FILES['image']['name'] as $index => $image_name){
    if (is_uploaded_file($_FILES['image']['tmp_name'][$index])) {
      move_uploaded_file($_FILES['image']['tmp_name'][$index], '/images/' . $image_name);
    }
  }
}

Snapshot

Simple Dynamic Multiple File Uploader

Simple Dynamic Multiple File Uploader

Debugging Note

  • Make sure the dynamically added inputs meet the HTML standard by enclosing in a valid <form> inherently. Codes like this won’t work:
    <table>
      <tr>
        <td>
          <form ...>
            <input ...>
        </td>
        <td>
          <div id="image_container">
            <input name="image[]">
            <input name="image[]">
            <!-- more input added here by javascript -->
          </div>
        </td>
      </tr>
    </table>
    </form>

    The original inputs (image[] here) can still passed here for most modern browsers, but the added inputs by Javascript will not passed and lose in the post variables.

  • IE seems not support type declaration of the input in javascript. That is, you need to declare the input type in the createElement. Details are here
      //use browser sniffing to determine if IE or Opera (ugly, but required)
      var isOpera, isIE = false;
      if(typeof(window.opera) != 'undefined'){isOpera = true;}
      if(!isOpera && navigator.userAgent.indexOf('Internet Explorer')){isIE = true);
     
      if(!isIE){
        var newfileBox = container.appendChild(document.createElement("input"));
        newfileBox.type = 'file';
        newfileBox.name = 'image[]';
        newfileBox.setAttribute('onchange','addImageBox(this, ' + (id+1) + ');');
      } else {
        myNewField = document.createElement('<input name="tags"/>');
        var newfileBox = container.appendChild(document.createElement("<input type='file' name='image' onchange='addImageBox(this, " + (id+1) + ");'>");
      }

Handling 2D array of HTML Form Elements in JavaScript and PHP

September 20th, 2012 No comments

I am working on the checkout page, while the quantity of colours of the products can be selected. The page contains:

  • a list of products
  • each product may or may not have a list of colour options

So I am looking for a form that can pass a 2D array, that can be handled easily by JS and PHP. Here is a good article about it.

However, the article is only about a 1D array. For my case I did a bit modification:

foreach($products as $product){
  ...
  if(isset($product['colours']){
    echo '<select name="colour_qty[' . $product['id'] . ']">'
    ...
    echo '<input type="hidden" name="colour_product_id[]" value="' . $product['id'] . '">
  }
  ...
}

Then the name of the select boxes would be colour_qty[123][], colour_qty[123][], colour_qty[123][], colour_qty[234][], etc.

To handle the inputs from PHP we use:

foreach($_POST['colour_product_id'] as $index => $id){
  $total_colour_qty = 0;
  foreach($_POST['colour_qty[' . $id . ']'] as $colour_qty)
    $total_colour_qty += (int)$colour_qty;
  echo 'Total colour quantities for product #' . $id . ': ' . $total_colour_qty . '<br>';
}

For JS we first get the list of product IDs, which need to be handled, into an array called $colour_products_ids, then we have:

var ids = new Array("<?php echo implode('","', $colour_products_ids) ?>");
for(var i=0; i<ids.length; i++){
  var colour_qty_inputs = document.shopping_cart.elements["colour_qty[" + ids[i] + "][]"];
  if('null' != colour_qty_inputs){
    var total_colour_qty = 0;
    for(var j=0; j<colour_qty_inputs.length; j++){
      total_colour_qty += parseInt(colour_qty_inputs[j].value);
    }
  }
  alert('Total colour quantities for product #' + ids[i] + ': '+ total_colour_qty);
}