lang/js/ AjaxUpload


See SendAjax

This is a simple example using Javascript and PHP

Example 1

AJAX Core

The core that makes it work is

        xhttp.open("POST", ".upload", true);
        xhttp.onload = function (event) {
          const responseText = this.responseText
          console.log({responseText})
          const response = JSON.parse(responseText)
          console.log({response})
          const status = xhttp.status
          if (status == 200) {
            const { result, error, files } = response
            if (result === "error") {
              display_error(error)
            } else {
              on_successful_upload(files, result)
            }
          } else {
            // this will happen if you don't have write permission at time of upload (a 403)
            display_error(`status ${status}: ${responseText}`)
          }
        }
        xhttp.send(form_data);

and

foreach ($_FILES['file']['name'] as $key=>$val) {
  $filename = $_FILES['file']['name'][$key];
  $filename = preg_replace('/[^a-zA-Z0-9_\-@\. ]+/',"_",$filename);
  $tmp_name = $_FILES['file']['tmp_name'][$key];
  $target = trim($subdir,"/")."/".$filename;
  if( ! $wiki->valid_file_path($target) ) {
    array_push($files_results,make_error($filename,"Filename '$filename' is not acceptable"));
    $failures++;
  } else {
    // filename ok
    try {
      $storage->store_uploaded($tmp_name,$target);
      array_push($files_results,array("filename"=>$filename,"result"=>"success","error"=>null));
      $successes++;
    } catch( Exception $e ) {
      array_push($files_results,make_error($filename,"Failed to move '$filename' -- ".$e->getMessage()));
      $failures++;
    }
  }
}

everything else below is a wrapper

Javascript

//
// Code adapted from https://artisansweb.net/drag-drop-file-upload-using-javascript-php/
//
(function() {
  window.addEventListener("load",_ => {
    let fileobj
    function upload_file(e) {
        console.log({msg:"upload file"})
        e.preventDefault()
        ajax_file_upload(e.dataTransfer.files)
    }
    function filename_is_image(filename) {
      return filename.match(/\.(jpg|jpeg|jfif|png|webp|gif|svg)$/)
    }

    function on_successful_upload(files, result) {
      console.log({msg:"upload",files,result})
      const successful_files = files.filter(x => x.result === "success" )
      let msg
      if( result === "partial" ) {
        msg = `Partial success: ${successful_files.length}/${files.length} uploaded`
      } else {
        msg = `Success: ${successful_files.length}/${files.length} uploaded`
      }
      const msgarr = []
      for(let i=0; i<files.length; i++) {
        const f = files[i]
        const { filename, result, error } = f
        if( result === "error" ) {
          msgarr.push(`<span class='upload_error'>${filename} &mdash; ${error}</span>`)
        } else {
          const img = filename_is_image(filename) ? ` <img src='${filename}'/>` : ""
          msgarr.push(`<span class='upload_success'>${filename}${img}</span>`)
        }
      }
      msg += "<br/>\n" + msgarr.join("<br/>\n")
      // do something to tell the user the result
      display_notification(msg,true) // supply this function yourself
    }
    // ACTUAL UPLOADER
    function ajax_file_upload(files_obj) {
      console.log(files_obj)
      if (files_obj != undefined) {
        var form_data = new FormData();
        for (let i = 0; i < files_obj.length; i++) {
          console.log(files_obj)
          form_data.append('file[]', files_obj[i])
        }
        form_data.append('location',window.location.href)
        console.log(`uploading`, files_obj);
        display_notification(`Uploading ${Array.from(files_obj).map(x => x.name).join(", ")}`)
        var xhttp = new XMLHttpRequest();
        xhttp.open("POST", ".upload", true);
        xhttp.onload = function (event) {
          const responseText = this.responseText
          console.log({responseText})
          const response = JSON.parse(responseText)
          console.log({response})
          const status = xhttp.status
          if (status == 200) {
            const { result, error, files } = response
            if (result === "error") {
              display_error(error)
            } else {
              on_successful_upload(files, result)
            }
          } else {
            // this will happen if you don't have write permission at time of upload (a 403)
            display_error(`status ${status}: ${responseText}`)
          }
        }
        xhttp.send(form_data);
      }
    }
  })

})()

PHP

php
#
# Code adapted from https://artisansweb.net/drag-drop-file-upload-using-javascript-php/
#
function store_uploaded_file($tmp_name,$filename) {
  return move_uploaded_file($tmp_name,$filename);
}
function return_error(string $msg, int $response_code = 400) : void {
  http_response_code($response_code);
  file_put_contents("error.txt",$msg);
  echo json_encode(["error" => $msg]);
  die;
}
function return_json($obj) : void {
  echo json_encode($obj);
  die;
}

function make_error($filename,$error) {
  return array("filename" => $filename, "result"=> "error", "error"=>$error);
}

umask(0);
$status = "success";
$error = null;
$files_results = array();
$successes = 0;
$failures = 0;
if( ! isset($_POST) || ! array_key_exists('location',$_POST) ) {
  return_error("Invalid upload data -- no location");
}
$location = parse_url($_POST['location']);
$path = urldecode($location['path']);
$subdir = dirname($path);
foreach ($_FILES['file']['name'] as $key=>$val) {
  $filename = $_FILES['file']['name'][$key];
  $filename = preg_replace('/[^a-zA-Z0-9_\-@\. ]+/',"_",$filename);
  $tmp_name = $_FILES['file']['tmp_name'][$key];
  $target = trim($subdir,"/")."/".$filename;
  if( ! $wiki->valid_file_path($target) ) {
    array_push($files_results,make_error($filename,"Filename '$filename' is not acceptable"));
    $failures++;
  } else {
    // filename ok
    try {
      $storage->store_uploaded($tmp_name,$target);
      array_push($files_results,array("filename"=>$filename,"result"=>"success","error"=>null));
      $successes++;
    } catch( Exception $e ) {
      array_push($files_results,make_error($filename,"Failed to move '$filename' -- ".$e->getMessage()));
      $failures++;
    }
  }
}
$return_obj = array(
  "error"=> ($successes == 0 ? "No files uploaded" : null),
  "result"=> ($successes > 0 && $failures == 0 ? "success" : ($successes > 0 && $failures > 0 ? "partial" : "error" )),
  "files"=> $files_results
);
$json = json_encode($return_obj);
echo $json;
exit();