1

I am trying to create a web API that allows someone (well, preferably a program) to submit a large binary file and receive an ID for that file in return. I have some HTML with a form (method="POST") and an <input type="file" ...> element that can submit a file to some PHP code, using the standard multipart/form-data MIME type. The PHP generates the ID and prints it out as its result. Because the PHP simply prints the ID, as opposed to redirecting to another HTML page or generating HTML itself, it is not very pretty, but hopefully is sufficient for the intended use case of a programmatic file submit API.

So far, so good. It gets tricky when I want to have client-side code capture the returned ID and invoke other APIs with it. If the client is a web page with JavaScript, it seems like the client should use XMLHttpRequest, but it is not clear to me how to get that object to use the file the user selected with the file input control.

I would love for the same API to work both with manually operated web forms (for easy UI and testing), and purely programmatic invocation (like with JavaScript, curl/libcurl, etc.). I don't want the PHP to issue a redirect to another page with the ID in the query string, and I don't want to return HTML directly. I just want a simple file in, ID out API.

Since this is proving difficult I suspect I am going about things the wrong way. I am open to alternative designs, but I would prefer to keep things as simple as possible. I found a somewhat similar question, but it is too Java-centric and doesn't quite address my problem.

Community
  • 1
  • 1
Randall Cook
  • 6,728
  • 6
  • 33
  • 68
  • Is your question "How can I use JavaScript to upload a user selected file and capture the returned document?"? That seems to be the only problem you are having, but your concern otherwise seems to be with the design of the server side of this. – Quentin Oct 15 '12 at 06:17
  • More or less. The file can be user-selected (like in a form), or programmatically supplied (like from a script). The returned document is really just an ID, with whatever packaging makes sense, and that is usable by client-side JavaScript. My concern is that the server side code is compatible with my client-side use cases. I am happy to adjust either to solve the problem. – Randall Cook Oct 15 '12 at 06:21

2 Answers2

1

I had to do something similar, and what I ended up doing was submitting the form to a hidden iframe. The response from the php can then simply be retrieved in an iframe onload handler.

In fact, here is the code I used:

    $('submitdestination').onload=function(){
        var appID=this.contentDocument.body.children[0].innerHTML;
        //did something with appID
        new mBox.Notice({type: 'ok',delayClose: 1000,content: 'Data saved.',position: {y: 'bottom',x: 'right'}});//displayed message
    }
    $('cvdetails').submit();

Note: submitdestination is my iframe. cvdetails is my form. The target for the form was set to submitdestination. Also, I am using Mootools, in case any one noticed the missing hash in my dollar arguments.

Here is a stripped down version of the HTML I used (although the iframe is unchanged):

<form id="cvdetails" name="cvdetails" action="scripts/upload.php" method="post" enctype="multipart/form-data" target="submitdestination" autocomplete="off">
    <button type="button" id="save" class="mainbutton">Save</button>
</form>
<iframe id="submitdestination" name="submitdestination" style="display:none" ></iframe>

The save button had a click handler that could be reduced to:

$('save').addEvent('click',function(evt){evt.stop();$('cvdetails').submit();})
Asad Saeeduddin
  • 46,193
  • 6
  • 90
  • 139
  • As I was researching this, I saw mention of the hidden iframe approach, but I didn't think to capture the response in the `onload` handler. Could you please link to or post some sample code? I think people would benefit from seeing it all together. – Randall Cook Oct 15 '12 at 06:26
  • I have posted the code. My case is more similar to yours than I had thought, although I was outputting one or two elements in the body tag of the response html. The first child contained the ID of the applicant (this was for generating company format word CVs) – Asad Saeeduddin Oct 15 '12 at 06:31
  • Sorry to bug you again, @Asad, but could you also post the HTML for the hidden iframe and the form that submits to it? I'de love to see all the components at once. – Randall Cook Oct 16 '12 at 01:02
  • I cannot post my exact HTML, which is generated by php, but I am adding a simplified version to the answer above. I'd like to make a fiddle for this, but it pertains simultaneously to client side and server side script, which complicates things. – Asad Saeeduddin Oct 16 '12 at 06:15
  • Thanks for the examples, @Asad. You really helped me solve the problem. Enjoy the 25 points. :) – Randall Cook Oct 16 '12 at 19:05
0

Thanks to @Asad's help I was able to get things working the way I wanted. Putting it all together, I have essentially this code:

<html>
    <head>
        <script type="text/javascript">

window.onload = function(){
    setUploadID(-1);
    document.getElementById('hidden_iframe').onload = captureUploadID;
}

function setUploadID(id)
{
    document.getElementById('upload_id').innerHTML = id;
}

function captureUploadID()
{
    var upload_id = this.contentDocument.body.childNodes[0].textContent;
    setUploadID(upload_id);
}
        </script>
    </head>
    <body>
        <form action="upload.php" enctype="multipart/form-data" method="POST" target="hidden_iframe">
            File: <input type="file" name="media" /><br>
            <input type="submit" value="Upload" />
        </form>
        <br>
        Upload ID: <span id="upload_id"></span>
        <iframe id="hidden_iframe" style="display: none;"></iframe>
    </body>
</html>
Randall Cook
  • 6,728
  • 6
  • 33
  • 68