I have written a mechanism to upload a file using AJAX technology (pure javascript) in CodeIgniter.
Explanation:
1- I have written a script.js file which is responsible to handle AJAX/Javascript process of the upload.
2- I have written a controller in CodeIgniter which receives request from AJAX to upload the file.
3- I have written a simple HTML page
PROBLEM: When I hit the upload button, simply nothing happens! No error is shown. I think there is a problem with the transfer of data between javascript and php. Because I have used an almost similar code in regular php page and has been successful.
Here are files:
This is JAVASCRIPT
// JavaScript Document
var doUpload = function(event){
// globally used variables in this function
var progressBar = document.getElementById('progressBar');
event.preventDefault(); // prevents the default action of an element
event.stopPropagation();
// get the file-input id
var fileId = document.getElementById('file');
// this variable makes an object which accept key/value pairs which could be sent via ajax.send
var formObj = new FormData();
// append currently selected file to the dataObject
formObj.append('file', fileId.files[0]);
// this is a variable to check in the php script (controller if the codeIgniter is used)
formObj.append('error-check', true);
formObj.append('finish-check', true);
// let's make the ajax request object
var ajaxReq = new XMLHttpRequest();
// PROGRESS OF THE FILE /////////////////////////////////////////////
// now trigger a function during the progress-process of the file-upload process
ajaxReq.upload.addEventListener('progress', function(event){
console.log('this is a very good.');
// first let's get the amount of the file loaded. it is in decimals
var percent = event.loaded / event.total;
// get the name of the element that the progress-indicator is outputted there
if(event.lengthComputable) // if a file is inserted and everything is just OK for uploading
{
if(progressBar.hasChildNodes()) // cleans the div container for a new progress to display
{
progressBar.removeChild(progressBar.firsChild);
}
progressBar.appendChild(document.createTextNode('The Progress So Far: '+percent*100+' %'));
}
// END OF PROGRESS OF THE FILE /////////////////////////////////////////////
// LOAD OF THE FILE /////////////////////////////////////////////
ajaxReq.upload.addEventListener('load', function(event){
progressBar.appendChild(document.createTextNode(" Completed!"));
});
// END OF LOAD OF THE FILE /////////////////////////////////////////////
// ERROR OF THE FILE /////////////////////////////////////////////
ajaxReq.upload.addEventListener('error', function(event){
progressBar.removeChild();
progressBar.appendChild(document.createTextNode("Failed to Upload the File."));
});
// END OF THE ERROR OF THE FILE /////////////////////////////////////////////
// JSON
// OPEN THE AJAX REQUEST
ajaxReq.open('POST', 'upload/uploader');
// Set the header of the POST request
ajaxReq.setRequestHeader('Cache-Control', 'no-cache');
// send the file. remember, we shoud pass a formData object as an argument to the ajaxRequest.send();
ajaxReq.send(formObj);
});
}
window.addEventListener('load', function(event)
{
// get the submit id of the form
var submitButton = document.getElementById('submit');
submitButton.addEventListener('click', doUpload);
});
This is PHP Controller in CodeIgniter
<?php
class Upload extends CI_Controller
{
function index()
{
$this->load->view('pages/form');
}
function uploader ()
{
// define the required settings for the upload library to instanciate
$config['upload_path'] = './uploads/';
$config['allowed_types'] = 'gif|jpg|png|doc|txt';
$config['max_size'] = 1024 * 8;
$config['encrypt_name'] = TRUE;
// load the upload library
$this->load->library('upload', $config);
if(!$this->upload->do_upload('file'))
{
$data['error'] = $this->upload->display_errors();
//$this->load->view('pages/form', $data);
json_encode($data['error']);
}
else
{
$data['uploaded'] = $this->upload->data();
//$this->load->view('pages/form', $data);
}
}
}
This is the HTML
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Upload Form With Ajax</title>
<script src="<?php echo base_url(); ?>js/script.js" type='text/javascript'></script>
</head>
<body>
<div id='error' style='color: red;height: 40px; width: 200px;'>
<?php
if(!empty($error)){echo $error; }
?>
</div>
<form id='form' name='form' enctype="multipart/form-data" >
<input type='file' name='file' id='file'/>
<input type='submit' name='submit' id='submit' value='Upload File' />
</form>
<div style='height: 200px; width: 300px; color: red; padding: 10px; background-color: #CCC;' id='progressBar'></div>
</body>
</html>
In script.js move:
// OPEN THE AJAX REQUEST
ajaxReq.open('POST', 'upload/uploader');
// Set the header of the POST request
ajaxReq.setRequestHeader('Cache-Control', 'no-cache')
// send the file. remember, we shoud pass a formData object as an argument to the xhruest.send();
ajaxReq.send(formObj);
outwith the progress event listener:
ajaxReq.upload.addEventListener('progress', function(event)
{
console.log('this is a very good.');
// first let's get the amount of the file loaded. it is in decimals
var percent = event.loaded / event.total;
// get the name of the element that the progress-indicator is outputted there
if(event.lengthComputable) // if a file is inserted and everything is just OK for uploading
{
if(progressBar.hasChildNodes()) // cleans the div container for a new progress to display
{
progressBar.removeChild(progressBar.firsChild);
}
progressBar.appendChild(document.createTextNode('The Progress So Far: '+percent*100+' %'));
}
// END OF PROGRESS OF THE FILE /////////////////////////////////////////////
// LOAD OF THE FILE /////////////////////////////////////////////
ajaxReq.upload.addEventListener('load', function(event)
{
progressBar.appendChild(document.createTextNode(" Completed!"));
});
// END OF LOAD OF THE FILE /////////////////////////////////////////////
// ERROR OF THE FILE /////////////////////////////////////////////
ajaxReq.upload.addEventListener('error', function(event)
{
progressBar.removeChild();
progressBar.appendChild(document.createTextNode("Failed to Upload the File."));
});
// END OF THE ERROR OF THE FILE /////////////////////////////////////////////
// JSON
});
// OPEN THE AJAX REQUEST
ajaxReq.open('POST', 'upload/uploader');
// Set the header of the POST request
ajaxReq.setRequestHeader('Cache-Control', 'no-cache')
// send the file. remember, we shoud pass a formData object as an argument to the ajaxRequest.send();
ajaxReq.send(formObj);
There was another problem in my code the prevented the execution: I used:
ajaxReq.upload.addEventListener`
I had to omit the upload:
ajaxReq.addEventListener
Related
For creating a .zip file for checked items with selectbox, i need a response back from the php that leads to the path the .zip file is stored.
This is my ajax call:
// AJAX for Checkbox download
$(document).on('click' , '.cb_down' , function() {
var checkboxes_down = [];
$('.rafcheckbox').each(function() {
if(this.checked) {
checkboxes_down.push($(this).val());
}
});
checkboxes_down = checkboxes_down.toString();
$.ajax({
url:"",
method:"POST",
data:{ checkboxes_down:checkboxes_down },
success:function(response){
window.location = response; // this should lead me to the zip file
}
//.........
My php:
// Multiple download (checkboxes)
if(isset($_POST["checkboxes_down"])) {
// create a tmp folder for the zip file
$tmpfolder = $MainFolderName.'/tmpzip';
if (!is_dir($tmpfolder)) {
mkdir($tmpfolder, 0755, true);
}
$checkboxfiles = explode("," , $_POST["checkboxes_down"]);
$filename = "archive.zip";
$filepath = $tmpfolder."/";
foreach($checkboxfiles as $checkboxfile) {
Zip($checkboxfile, $tmpfolder."/archive.zip"); // Zip is a function that creates the .zip file
}
// header come here
echo $filepath . $filename; // the path to the .zip file
exit;
The .zip file is successful created. I checked it.
The problem is: i do not get the response back from the php script.
So i can not download the .zip file.
What i am doing wrong?
! I changed the echo to 'zip file is created' but even that echo i do not receive as response back
I have an existing API that only accepts JSON values via a POST, it responds with a downloadable zip file that is only session based, not on a server. I wanted to create an HTML form that could be filled out and POST the JSON values to the API then receive the download. Once the API receives the JSON it will respond with a Zip file that should be downloaded through the browser. I spent a lot of time searching for how to do this and eventually pulled together the components to make it happen. I wanted to share it here because I saw many other people searching for the same thing but with no clear answers or script that worked, lost of GET examples but no POST with in memory server data. In fact may folks said it just couldn't be done with POST.
<script src="https://code.jquery.com/jquery-1.9.1.js"></script>
<script>
$(function () {
$('form').on('submit', function (event) {
//Function montiors for the form submit event
event.preventDefault(); // Prevents the default action of the form submit button
var jsonData = '{"PONumber":"' + form1.PONumber.value //JSON data being submitted to the API from the HTML form
+ '","CompanyName":"' + form1.CompanyName.value
+ '","CompanyID":"' + form1.CompanyID.value
+ '","ProductName":"' + form1.ProductName.value
+ '","Quantity":"' + form1.quantity.value
+ '","Manufacturer":"' + form1.Manufacturer.value + '"}';
var xhr = new XMLHttpRequest();
xhr.open('POST', 'api_page.php', true); //The POST to the API page where the JSON will be submitted
xhr.responseType = 'blob';
xhr.setRequestHeader('Content-type', 'application/json'); //Additional header fields as necessary
xhr.setRequestHeader('Authorization', 'Bearer ' + 'eyJ0eXAiOiJKV1QiLCJhbGciO----< SNIP >---547OWZr9ZMEvZBiQpVvU0K0U');
xhr.onload = function(e) {
if (this.status == 200) {
var blob = new Blob([this.response], {type: 'application/zip'}); //We're downloading a Zip file
var downloadUrl = URL.createObjectURL(blob);
var a = document.createElement("a");
a.href = downloadUrl;
a.download = "download_file.zip"; //The name for the downloaded file that will be saved
document.body.appendChild(a);
a.click(); //Automatically starts the download
} else {
alert('Unable to download file.')
}
};
xhr.send(jsonData); //Sends the JSON data to the destination POST page
});
});
</script>
<form method="post" name="form1" id="form1" action="" >
<td><center><input name="submit" type="submit" value="submit"></center></td>
<td ><strong>ENTER QUANTITY OF UNITS: </strong></td><td> </td>
<td><input name="quantity" type="text" size="17" value="<?php echo $row['value'];?>"></td>
</form>
Here is the code for the PHP server side of the application. The first part is to receive the request.
//Receive the incoming JSON data from the form POST
$jsonRequest = trim(file_get_contents("php://input"));
//Attempt to decode the incoming RAW post data.
$requestDecoded = json_decode($jsonRequest, true);
//Do something with the data and then respond with a zip file.
Here is the PHP code that sends the Zip file back to the original requesting page for download.
$fp = fopen('php://output', 'w'); //Creates output buffer
$mfiles = $yourZipFile
if($fp && $mfiles) {
header("Cache-Control: no-cache");
header("Content-Type: application/zip");
header("Content-Disposition: attachment;
filename=\"".basename($zipName)."\";");
header("Content-Transfer-Encoding: binary");
header("Content-Length: " .strlen($mfiles));
header("Response-Data: ".$responseData);
ob_end_clean();
if (fputs($fp, $mfiles, strlen($mfiles))===FALSE){
throw new Exception($e);
}
}
else {
throw new Exception($e);
}
Place the javascript code in the body of your HTML page and it should work just fine. I hope this helps someone else out there in the same position. I've tried to describe each component as best I can and include all of the pieces to make it work.
Request: Browser --> HTML form --> JSON --> POST --> PHP
Response: PHP --> zip file --> Browser Download --> Local PC
I am attempting to add an "Upload Image" feature to my AjaxChat window. The upload to the server works great, but now I need to be able to return the tmp_name/location of the file that was uploaded. In my Javascript I have the following (main) code (some setup code has been omitted because it is unnecessary -- The upload works as expected):
// Set up request
var xhr = new XMLHttpRequest();
// Open connection
xhr.open('POST', 'sites/all/modules/ajaxchat/upload.php', true);
// Set up handler for when request finishes
xhr.onload = function () {
if (xhr.status === 200) {
//File(s) uploaded
uploadButton.innerHTML = 'Upload';
} else {
alert('An error occurred!');
}
};
// Send data
xhr.send(formData);
My PHP code ("upload.php") is as follows:
<?php
$valid_file = true;
echo '<script type="text/javascript">alert("PHP Code Reached");</script>';
if($_FILES['photo']['name']) {
//if no errors...
if(!$_FILES['photo']['error']) {
//now is the time to modify the future file name and validate the file
$new_file_name = strtolower($_FILES['photo']['tmp_name']); //rename file
if($_FILES['photo']['size'] > (1024000)) { //can't be larger than 1 MB
$valid_file = false;
$message = 'Oops! Your file\'s size is to large.';
exit("$message");
}
//if the file has passed the test
if($valid_file) {
//move it to where we want it to be
move_uploaded_file($_FILES['photo']['tmp_name'], '/var/www/html/images'.$new_file_name);
$message = 'Congratulations! Your file was accepted.';
exit("$message");
}
}
//if there is an error...
else {
//set that to be the returned message
$message = 'Ooops! Your upload triggered the following error: '.$_FILES['photo']['error'];
exit("$message");
}
}
?>
I can tell my PHP code is being run because the image uploads to the server. However, I read that I could generate a Javascript "alert" popup from within the PHP using the following code:
echo '<script type="text/javascript">alert("PHP Code Reached");</script>';
But the above line does not seem to be doing anything. Is this expected since I'm using an XMLHttpRequest, rather than running the PHP directly?
Ultimately my goal is to pass the name of the uploaded file back to the Javascript that called the PHP so that I can create the image url, put it in img tags, and send it to the chat window using ajaxChat.insertText() and ajaxChat.sendMessage(). I'm not sure if this is possible the way I'm running my PHP, though. How would one go about doing this?
When you use XMLHttpRequest, the output of the server script is in the responseText of the object. So you can do:
xhr.onload = function () {
if (xhr.status === 200) {
//File(s) uploaded
uploadButton.innerHTML = xhr.responseText;
} else {
alert('An error occurred!');
}
};
If you want to send back multiple pieces of information, such as an informative message and the name of the file, you can use JSON to encode an associative array, which will become a Javascript object when you parse it.
This is a tangent from the question here:
Returning value to Javascript from PHP called from XMLHttpRequest
I am adding an "image upload" button to my AjaxChat. I am using an XMLHttpRequest to send the image to the server, where I run a PHP script to move it to my images folder. Below is the Javascript function in charge of opening the XMLHttpRequest connection and sending the file:
function uploadImage() {
var form = document.getElementById('fileSelectForm');
var photo = document.getElementById('photo');
var uploadButton = document.getElementById('imageUploadButton');
form.onsubmit = function(event) {
event.preventDefault();
// Update button text
uploadButton.innerHTML = 'Uploading...';
//Get selected files from input
var files = photo.files;
// Create a new FormData object
var formData = new FormData();
// Loop through selected files
for (var i = 0; files.length > i; i++) {
var file = files[i];
// Check file type; only images are allowed
if (!file.type.match('image/*')) {
continue;
}
// Add file to request
formData.append('photo', file, file.name);
}
// Set up request
var xhr = new XMLHttpRequest();
// Open connection
xhr.open('POST', 'sites/all/modules/ajaxchat/upload.php', true);
// Set up handler for when request finishes
xhr.onload = function () {
if (xhr.status === 200) {
//File(s) uploaded
uploadButton.innerHTML = 'Upload';
var result = xhr.responseText;
ajaxChat.insertText('\n\[img\]http:\/\/www.mysite.com\/images' + result + '\[\/img\]');
ajaxChat.sendMessage();
} else {
alert('An error occurred!');
}
form.reset();
};
// Send data
xhr.send(formData);
}
}
Here is upload.php:
<?php
$valid_file = true;
if($_FILES['photo']['name']) {
//if no errors...
if(!$_FILES['photo']['error']) {
//now is the time to modify the future file name and validate the file
$new_file_name = strtolower($_FILES['photo']['tmp_name']); //rename file
if($_FILES['photo']['size'] > (1024000)) { //can't be larger than 1 MB
$valid_file = false;
}
//if the file has passed the test
if($valid_file) {
//move it to where we want it to be
move_uploaded_file($_FILES['photo']['tmp_name'], '/var/www/html/images'.$new_file_name);
$message = $new_file_name;
exit("$message");
}
}
}
?>
I currently have the multiple image upload disabled, so the "Loop through selected files" only executes once.
The upload worked for a little bit on my PC, but then I tried uploading an image from my phone. When I did so, the entire server (and my browser) crashed, presumably due to an infinite loop somewhere. Every time I close my browser and log back in, or restart the server, or restart my computer, it hangs and eventually crashes again (on my PC or on my phone). I have been unable to find the script that is causing the issue. I get the feeling it's right under my nose. Does anyone see the problem? If you need the HTML form code then I can provide that, but I don't think it's necessary.
I've created a functionality on my website where user's can change the background image via upload. The procedure is following:
User goes to settings page and selects an image file to be uploaded. After selecting image, the browser will output it so that user can preview
it before actually saving it's file to in to the folder and filepath in to the database. After that, if user is happy with the result, he can save it to the
folder by pressing "Upload Background Image" button.
All of the above is handled with AJAX.
I am having trouble to just output the image to the browser without actually saving it twice, first into tests folder and after that into backgrounds folder.
I'm using CodeIgniter as my backend framework and jQuery for my AJAX requests.
Here are my methods for outputting (testing) and saving the image:
public function test_image()
{
if($this->input->is_ajax_request())
{
// This part of code needs to be replaced to only just output the image (return it as a JSON), not actually saving it to another a folder
$ext = pathinfo($_FILES['userfile']['name'], PATHINFO_EXTENSION);
$new_img_name = random_string('unique'). "." . $ext;
$config['upload_path'] = './public/images/uploads/tests';
$config['allowed_types'] = 'gif|jpg|jpeg|png';
$config['max_size'] = '1000000';
$config['max_width'] = '2000';
$config['max_height'] = '1600';
$config['file_name'] = $new_img_name;
$this->load->library('upload', $config);
if (!$this->upload->do_upload()) {
$this->output->set_content_type('application_json');
$this->output->set_output(json_encode(array('image_errors' => $this->upload->display_errors('<p class="text-center">','</p>'))));
return false;
} else {
$this->output->set_content_type('application_json');
$this->output->set_output(json_encode(array('userfile' => $new_img_name)));
}
} else {
echo "Not an ajax request";
}
}
// This method works properly
public function upload_background_image()
{
if (isset($_POST))
{
$ext = pathinfo($_FILES['userfile']['name'], PATHINFO_EXTENSION);
$new_img_name = random_string('unique'). "." . $ext;
$config['upload_path'] = './public/images/uploads/backgrounds';
$config['allowed_types'] = 'gif|jpg|jpeg|png';
$config['max_size'] = '1000000';
$config['max_width'] = '2000';
$config['max_height'] = '1600';
$config['file_name'] = $new_img_name;
$this->load->library('upload', $config);
if (!$this->upload->do_upload()) {
$this->output->set_content_type('application_json');
$this->output->set_output(json_encode(array('image_errors' => $this->upload->display_errors('<p class="text-center">','</p>'))));
return false;
} else {
$this->load->model('user_model');
$user_id = $this->session->userdata('user_id');
$upload_photo = $this->user_model->updateUserInfo($user_id, ['body_background_url' => $new_img_name]);
if ($upload_photo === true) {
$this->session->set_userdata(['body_background_url' => $new_img_name]);
redirect(base_url());
}
}
}
}
And here's my AJAX:
$("#bg-cover-file").change(function(e) {
e.preventDefault();
var form = $(this).closest('form');
form.ajaxSubmit({
dataType: 'json',
beforeSubmit: function() {
},
success: function(response) {
if(response.userfile) {
// Output the image
$('.test-image').attr('src', response.userfile);
$('span.file-input').hide();
// Change the form action attribute
var new_path = 'uploads/upload_background_image';
form.attr('action', new_path);
} else {
$('#error-modal').modal('show');
$("#error-body").html(response.image_errors);
return false;
}
}
});
return false;
});
--Working Demo--
I have put comments in this demo to explain what the steps are so please read them.
If you don't understand anything in this answer please leave a comment below and i will update the answer until you understand line for line. You don't learn from copy/paste so please be sure to understand the answer.
function MyFunction() {
var img=document.getElementById('BackgroundImage');
var Status=document.getElementById('Status');
var savebtn=document.getElementById('savebtn');
/* SetBG will target the body tag of the web page.
You can change this to any element -
var SetBG=document.getElementById('YourID').style;
*/
var SetBG=document.body.style;
//Split the image name
var fileExt=img.value.split('.');
//Use the last array from the split and put to lowercase
var fileformat=fileExt[fileExt.length -1].toLowerCase();
// Check the file extension (Image formats only!)
if((fileformat==='jpg')||(fileformat==='gif')||(fileformat==='png')||(fileformat==='jpeg')) {
if (img.files && img.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
//----Image is ready for preview.
SetBG.background='url('+e.target.result+') no-repeat center center fixed';
/*---- Optional, Set background as cover ---*/
SetBG.backgroundSize="cover";
SetBG.OBackgroundSize="cover";
SetBG.webkitBackgroundSize="cover";
//--Hide Loading Message
Status.style.display="none";
//----- Display (Save/Upload button?)
savebtn.style.display="block";
}
/*-------Reading File....
Display a message or loading gif for large images to be processed?
*/
Status.innerHTML="Loading...";
Status.style.display="block";
savebtn.style.display="none";
reader.readAsDataURL(img.files[0]);
}
}else{
/*----User file input not accepted (File isn't jpg/gif/png/jpeg)
Empty the input element and set the background to default.
*/
Status.innerHTML="Format not accepted";
Status.style.display="block";
savebtn.style.display="none";
SetBG.background='white';
document.getElementById('BackgroundImage').value='';
}
}
#Status{display:none;background:white;color:black;font-size:16pt;}
#savebtn{display:none;}
<div id="Status"></div>
<input type="file" id="BackgroundImage" onchange="MyFunction()"/>
<button id="savebtn" onclick="alert('Now upload the image');">Upload and save</button>
I hope this helps. Happy coding!
This may help you
let assume your browse button's id is bg-cover-file and the id of the image tag where you want to display the image preview_image
$(document).on("change", "#bg-cover-file", function(event)
{
if (this.files && this.files[0])
{
var reader = new FileReader();
reader.onload = function (e)
{
$('#preview_image').attr('src', e.target.result);
}
reader.readAsDataURL(this.files[0]);
}
});
function MyFunction() {
var img=document.getElementById('BackgroundImage');
var Status=document.getElementById('Status');
var savebtn=document.getElementById('savebtn');
/* SetBG will target the body tag of the web page.
You can change this to any element -
var SetBG=document.getElementById('YourID').style;
*/
var SetBG=document.body.style;
//Split the image name
var fileExt=img.value.split('.');
//Use the last array from the split and put to lowercase
var fileformat=fileExt[fileExt.length -1].toLowerCase();
// Check the file extension (Image formats only!)
if((fileformat==='jpg')||(fileformat==='gif')||(fileformat==='png')||(fileformat==='jpeg')) {
if (img.files && img.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
//----Image is ready for preview.
SetBG.background='url('+e.target.result+') no-repeat center center fixed';
/*---- Optional, Set background as cover ---*/
SetBG.backgroundSize="cover";
SetBG.OBackgroundSize="cover";
SetBG.webkitBackgroundSize="cover";
//--Hide Loading Message
Status.style.display="none";
//----- Display (Save/Upload button?)
savebtn.style.display="block";
}
/*-------Reading File....
Display a message or loading gif for large images to be processed?
*/
Status.innerHTML="Loading...";
Status.style.display="block";
savebtn.style.display="none";
reader.readAsDataURL(img.files[0]);
}
}else{
/*----User file input not accepted (File isn't jpg/gif/png/jpeg)
Empty the input element and set the background to default.
*/
Status.innerHTML="Format not accepted";
Status.style.display="block";
savebtn.style.display="none";
SetBG.background='white';
document.getElementById('BackgroundImage').value='';
}
}
#Status{display:none;background:white;color:black;font-size:16pt;}
#savebtn{display:none;}
<div id="Status"></div>
<input type="file" id="BackgroundImage" onchange="MyFunction()"/>
<button id="savebtn" onclick="alert('Now upload the image');">Upload and save</button>