I want to build a web service that will process some files.
Here is what I want to do:
User uploads a file to the server using "upload form", the file is saved as a temporary file on the server-side
Server-side python script processes the temporary file and produces some statistics (for example, number of lines and words in the file)
The statistics are displayed near the "upload form"
The question here is: I would like the file to be processed in the background just after it is uploaded, and after it is done, .append() the produced results to the current view. I do not want to assign a script to <form action="processing_script.php">... because the user will be redirected to the processing_script.php after clicking the Upload button.
Any clues? Maybe some neat ajax call?
function ajaxRequest(){
var activexmodes=["Msxml2.XMLHTTP", "Microsoft.XMLHTTP"] //activeX versions to check for in IE
if (window.ActiveXObject){ //Test for support for ActiveXObject in IE first (as XMLHttpRequest in IE7 is broken)
for (var i=0; i<activexmodes.length; i++){
try{
return new ActiveXObject(activexmodes[i])
}
catch(e){
//suppress error
}
}
}
else if (window.XMLHttpRequest) // if Mozilla, Safari etc
return new XMLHttpRequest()
else
return false
}
function postFile(){
var mypostrequest=new ajaxRequest()
mypostrequest.onreadystatechange=function(){
if (mypostrequest.readyState==4){
if (mypostrequest.status==200 || window.location.href.indexOf("http")==-1){
document.getElementById("my_Result_tag").innerHTML=mypostrequest.responseText //this is where the results will be put!
}
else{
alert("An error has occured making the request")
}
}
}
var file = document.getElementById("my_file");
var parameters="file="+file //i am not sure of this peice though
mypostrequest.open("POST", "basicform.php", true)
mypostrequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
mypostrequest.send(parameters)
}
Yeah, you'll need ajax for that. Create the form as usual, then submit it using Ajax. Form handling can be done as usual.
If you google 'file upload Ajax' I'm sure you can find everything you need :)
yeah, i'd made second ajax request and run it with schedule (e.g. every 10 seconds). it will query the server if uploaded file is processed. the server may even do the file processing in external program. the php-script that accepts second ajax request checks some READY status and give client the answer YES/NO/FAILED. when client accepts YES answer it refirects user to the RESULTS PAGE. if it accepts NO, it alerts user the problem.
Related
I have an index.php that accepts multiple images via a file input element. When the user submits the form, the request is sent to a hidden iframe and the action file (upload.php) converts and moves the images to a new directory. I attached an oninput function via Javascript:
document.getElementById("new-upload").addEventListener("submit", function() {
trackUpload();
});
function trackUpload() {
var httpReq = new XMLHttpRequest();
setTimeout(function() {
console.log("started");
httpReq.open("GET", "progress.php");
httpReq.send();
console.log("sent");
httpReq.onreadystatechange = function() {
console.log("state change " + httpReq.readyState);
if (httpReq.readyState === 4) {
var httpRes = httpReq.responseText;
console.log(httpRes);
if (httpRes < 100) {
setTimeout(trackUpload, 500);
console.log("started");
} else {
//hide upload bar
}
}
}
}, 500);
}
When I hit the upload button, the files are uploaded and then my upload.php file is called and it converts the images. I confirmed that the images are all uploaded before the upload.php file is called by echoing var_dump($_SESSION["upload_progress_images"]) which returned the finished upload array only when session.upload_progress.cleanup was set to Off. I console logged start, sent, and state changes for my XMLHttpRequest and it is being started and sent after a delay of 0.5 seconds like it's supposed to. However, it doesn't change to state 2 until the upload.php file is done converting and moving all the files. (Which is when the iframe finishes loading.) So why doesn't the XMLHttpRequest register that it received the request until then? Is my server limited to processing one file at a time or is it the browser?
EDIT
I tried to access another php page on my website while the php upload script was running and it didn't load until images were done loading. So that means that PHP can only do one thing at a time? If so, how would I accomplish my task above?
I want to make an upload page for my site so that documents get uploaded asynchronously, I tried using AJAX, but AJAX has a limited access to the users filesystem, and when the information is sent to the server only the file name appears without the directory, I would like suggestion on how to do this easily without using JQuery, and also I would like to know if there is a way to monitor the progress of a file upload, so that I could add a progress bar to my site.
function createXMLHttpRequestObject(){
var xmlHttp = 3;
if(window.ActiveXObject){
try{
//test for new version of internet Explorer
xmlHttp = new ActiveXObject("Msxml.XMLHTTP");
}
catch(e){
try{
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
catch(e){
xmlHttp = 2;
}
}
}
else{
try{
xmlHttp = new XMLHttpRequest();
}
catch(e){
xmlHttp = 1;
}
}
if(!xmlHttp){
alert("Error creating Objece");
}
else{
var xHttpArr = new Array();
xHttpArr.push(xmlHttp);
var i = xHttpArr.length - 1;
return xHttpArr[i];
}
}
function process(xmlHttp, i){
if(xmlHttp.readyState == 4 || xmlHttp.readyState == 0){
//value = encodeURIComponent( objRef.value );
xmlHttp.open("GET", "php/AjaxBody.php?value="+i, true);
xmlHttp.onreadystatechange = handleServerResponse;
xmlHttp.send(null);
}
else{
alert("Hold on");
}
}
function handleServerResponse(){
if(test.readyState == 1 || test.readyState == 2 || test.readyState == 3){
}
if (test.readyState == 4){
if(test.status == 200){
txtResponse = test.responseText;
bodyDiv = document.getElementById("body");
bodyDiv.innerHTML = txtResponse;
}
else{
alert("Error with the xmlHttp status");
}
}
/*
else{
alert("Error with the xmlHttp readystate: " + x.status);
} */
}
Above is the code that creates the Object
button.onclick = function() {
send = createXMLHttpRequestObject();
frmUpload = document.getElementById("frmUpload");
file = document.getElementById("fileUpload");
processSending(send, frmUpload);
}
Above when the process method is called to send the file,
on the server I try to echo the file path, only the the name appears, like this
<?php
echo $_GET['value'];
?>
First of all you are doing your file upload wrong. File uploads require you to do a proper POST request using forms as it requires the enctype form attribute to be multipart/form-data. Why? The browser sends the binary file data through the POST request and does the hard work of encoding the data correctly through the POST request to be read on the server. Any other way and you will just be getting the file name at the server (you can verify this with a tool like Fiddler).
Alright, then how do you do a file upload using AJAX? AFAIK it's not possible to read the user's file system directly (I think FileReader only allows reading through the sandboxed file system through the browser but I may be wrong here), so IMO there are 2 ways to go here:
Using a hidden iframe approach for the file upload. Google it you will find lots of info it.
Use a Flash based uploader. More on this at the end.
As far as getting the location of the file on the users file system using Javascript goes, forget about it. It's considered a security concern and many browsers only return the file name on reading the element value when using the HTML input file tag. (Unless you are thinking of using a flash component. More on that in the last point.)
Now coming to the progress bar issue. When your PHP script is actually run the entire file has already been uploaded to the server. So how to show a progress bar? A few (hackish) ways:
An old school approach is to create a CGI script on the server to handle the upload. The advantage? CGI scripts can be run during the upload allowing you to retrieve the actual byte level progress of the upload. But this also requires you to update the progress at some place on the server which you can poll (with a separate AJAX request) and show in the browser to the user.
Another most commonly used approach is using a flash based uploader (please don't kill me StackOverflow community). Yes it's still used by big names (I am looking at you Facebook). The advantage you will have is that you don't need any special scripts on the server. The Flash based client is fully aware of the number of bytes uploaded. Also you may have access to the actual file path string (note the use of may and string) which is not so openly possible with plain JS and HTML.
You could use a FileReader and read the file into an ArrayBuffer or a BinaryString and then use multiple requests to send for example 1 mb sized packages. The receiving php script would then have to 'rebuild' the file by appending each received part to it. This would also solve the problem of echoing the file path on the server as you can (and have to) decide where to save it before writing to it.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Best way to manage long-running php script?
I have to built a big email list.Everything works perfectly,but when i submit the form page is loading untill every email is send.So i want this email sending script run in background.and notice the user that script is runnign in background.
I cant use Ajax.
i want something like.. proc_open,exec,shell_exec..
You can have cron job which would run php script which will get queue from db and send email
On main script you just need to add emails to queue
I would use ajax only if you need progress bar. With ajax solution you would need to keep window open until it's ended.
You could build an AJAX call that calls the php script. This way, your site will still be operational while the request is fulfilled. And when it's finished, your AJAX will return and you can show a messagebox to the user.
For more information, check at least this and if you understand what AJAX is and what it does, use it with this
Ajax request would be the best choice for this. You can send a request using javascript and even report progress to user (which might require some additional work)
If you find ajax too difficult - run script in an iframe. This is not the most elegant, but the most simple method.
Submit the form with AJAX and update the progress in a Div
For example - write to some place "A"(db or file) current state of your script runtime: "complete"/"incomplete". After start script in background send to your user waiting page which using AJAX handling changes at "A".
This Ajax script will execute a PHP file on the background. It could also send the response to a HTML element if you want.
<script type="text/javascript" language="javascript">
function execute(filename,var1,var2,var3)
{
var xmlhttp;
if(window.XMLHttpRequest)
{
//Code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp = new XMLHttpRequest();
}
else if(window.ActiveXObject)
{
//Code for IE6, IE5
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
else
{
alert("Your browser does not support AJAX!");
}
var url = filename+"?";
var params = "var1="+var1+"&var2="+var2+"&var3="+var3;
xmlhttp.open("POST", url, true);
xmlhttp.onreadystatechange=function()
{
if(xmlhttp.readyState==4)
{
//Below line will fill a DIV with ID 'response'
//with the reply from the server. You can use this to troubleshoot
//document.getElementById('response').innerHTML=xmlhttp.responseText;
xmlhttp.close;
}
}
//Send the proper header information along with the request
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xmlhttp.setRequestHeader("Content-length", params.length);
xmlhttp.setRequestHeader("Connection", "close");
xmlhttp.send(params);
}
</script>
You can try to run the script through an ajax function as well if you don't want to set cron script.
PHP has an function that can keep an process running even if the user that requested the page leaves the page : ignore_user_abort if you check the comments there you can see this example :
<?php
ignore_user_abort(1); // run script in background
set_time_limit(0); // run script forever
$interval=60*15; // do every 15 minutes...
do{
// add the script that has to be ran every 15 minutes here
// ...
sleep($interval); // wait 15 minutes
}while(true);
?>
It IS an pure php cron job BUT, the risk with this script is that it continues indefinitely or atleast untill you reset/kill php.
Setting the set_time_limit(0); to set_time_limit(86400); would kill the script after an day.
This should point you in the right direction/.
IMPORTANT
After the problem by the OP, it is advisable to only run this script if you have SSH access to the server so you can KILL/RESTART php apache in case the server keeps hanging.
Also do not run the script on a LIVE server.
Full code can also be found here: https://gist.github.com/1973726 (partially version on jsfiddle http://jsfiddle.net/VaEAJ/ obviously couldn't have php running with jsfiddle)
I initially wrote some code which took a canvas element and saved it as an image (see working code here: https://gist.github.com/1973283) and afterwards I updated it so it could process multiple canvas elements but the main difference now is that the image data is passed through to my PHP script via jQuery ajax method rather than via a hidden form field.
Problem is the images appear to be blank. They are about 200kb each when generated so they obviously have some content but when you preview the image nothing shows and when I try and open the image in Adobe Fireworks or another photo application I can't open the file.
The image data appears to be coming through to the server fine, but I'm really not sure why now when I write the image using base64_decode it would mean the images that are generated would no longer be viewable? The only thing I can think of is that maybe the posting of data via ajax isn't sending all the data through and so it's generating an image but it's not the full content and so the image is incomplete (hence why a photo application can't open it).
When checking the post data in Firebug it suggests that the limit has been reached? Not sure if that's what the problem is?
The problem was actually with sending data via XHR. I was using jQuery ajax method initially and then I swapped it out for my own ajax abstraction but the problem was still occuring until someone on twitter suggested I use FormData to pass the data to the server-side PHP. Sample is as follows... (full code can be seen here: https://gist.github.com/1973726)
// Can't use standard library AJAX methods (such as…)
// data: "imgdata=" + newCanvas.toDataURL()
// Not sure why it doesn't work as we're only abstracting an API over the top of the native XHR object?
// To make this work we need to use a proper FormData object (no data on browser support)
var formData = new FormData();
formData.append("imgdata", newCanvas.toDataURL());
var xhr = new XMLHttpRequest();
xhr.open("POST", "saveimage.php");
xhr.send(formData);
// Watch for when the state of the document gets updated
xhr.onreadystatechange = function(){
// Wait until the data is fully loaded, and make sure that the request hasn't already timed out
if (xhr.readyState == 4) {
// Check to see if the request was successful
if (checkHTTPSuccess(xhr)) {
// Execute the success callback
onSuccessfulImageProcessing(card, newCanvas, ctx, getHTTPData(xhr));
}
else {
throw new Error("checkHTTPSuccess failed = " + e);
}
xhr.onreadystatechange = null;
xhr = null;
}
};
```
If you are not having Cross Origin SECURITY_ERR's (which your Fiddle suffers from, but as long as your images are on the same server they will be fine), and you are getting some data so you are probably having problems with your PHP. From the PHP user notes, you have to replace the spaces with +'s to decode base64 that has been encoded with Javascript.
$data = str_replace(" ", "+", $_POST['imgdata']);
file_put_contents("generated.png", base64_decode($data));
Is it possible? Now, I have done live chat, where with jquery's help I connect to .php file and check last modified time and if it is not as before, I retrieve messages. If it were possible in javascript I probably would save a lot of resources.
Thanks.
It's definitely possible if the server is sending an accurate Last-Modified header for that particular file:
var getMTime = function(url, callback) {
var xhr = XMLHttpRequest();
xhr.open('HEAD', url, true); // use HEAD - we only need the headers
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
var mtime = new Date(xhr.getResponseHeader('Last-Modified'));
if (mtime.toString() === 'Invalid Date') {
callback(); // dont want to return a bad date
} else {
callback(mtime);
}
}
}
xhr.send();
};
getMTime('url here', function(mtime) {
if (mtime) console.log('the mtime is:' + mtime.toISOString());
});
Short answer: there's no way but AJAX + a server-side script (in your case, jQuery + php)
Being a client-side script, javascript gets run on the client's computer, so if the file whose m-time you want to check is on the server, then you are correct to use AJAX and a server-side script. No other way will work.
If the file whose m-time you want to check is on the client's computer, then you're out of luck. Javascript is intentionally designed to be prevented from accessing the client's files. (It can only access cookies, which are on the client's computer, however, because the browser (not any javascript) loads those into its work environment.)
Maybe HTTP ETag headers could be used to check if the page has changed. The first response contains ETag and your client uses that for the following request. Your PHP server side code would then send 304 if the page has not been modified.
http://en.wikipedia.org/wiki/HTTP_ETag