I am writing a PHP web application using the CakePHP framework (v2.x). One of my views has a form that uploads a large video file to a third-party API. The files are large, so downloading may take a minute or two. So I submit the form with AJAX and show the user dancing hippo (or something else) so that they know that the wheels are still spinning. Here is a script that uses the jquery form plugin:
<script> var options = { //complete : callback_function..., //error : callback_function..., beforeSend : function() { $("#MediaSubmitForm").hide(); $("#MediaSubmitForm").after('<img class="hula-hippo" src="/img/hippo-hula.gif" />'); }, success : function(data){ $(".hula-hippo").hide(); $("#MediaSubmitForm").after("<h3>Upload complete!</h3>"); console.log(data); }, uploadProgress: function(event, position, total, percentComplete){ console.log(percentComplete); } }; $("#MediaSubmitForm").ajaxForm(options); </script>
In order not to expose our API key to the client, I submit the form to the controller action, which makes the actual POST request from the API server using curl. Here is this method (and one callback).
//uploads a video to a project through the API public function apiUpload( $tmp_filename, $project_hashed_id ) { $api_password = 'xxxxxxxxxx'; $username = 'api'; $data = array( 'api_password' => $api_password, 'file' => '@'.$tmp_filename, 'project_id' => $project_hashed_id ); $ch = curl_init(); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_URL, "https://upload.wistia.com" ); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); curl_setopt($ch, CURLOPT_NOPROGRESS, FALSE); curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, array($this, 'apiUploadCallback')); $result = curl_exec($ch); //***Note A*** curl_close($ch); return( json_decode($result) ); } //BE CAREFUL... PHP 5.5 Added the cURL resource as the first argument to the CURLOPT_PROGRESSFUNCTION callback protected function apiUploadCallback( $total_bytes_down_expected, $bytes_down_so_far, $total_bytes_up_expected, $total_bytes_up_so_far ) { if ($total_bytes_up_expected > 0) //error_log( round( ($total_bytes_up_so_far / $total_bytes_up_expected)*100) ); echo ( round( ($total_bytes_up_so_far / $total_bytes_up_expected)*100) ); //***Note B*** }
It works, but better if I can show the user the actual download progress. I figured out how to calculate this using the callback function (see ***Note B*** ), but I'm not sure how to pass it back to the page (where the user is waiting). I tried using jQuery uploadProgress , but it shows the progress of uploading the file to our server ... NOT the upload progress in the API. I tried to repeat the progress from the curl ( ***Note B*** ) callback, but it splashes out a series of numbers that are related to the json object returned by the api ( ***Note A*** ), which I also need. Something like that:
11112222233344444...9898989899999999999999{api:"response mixed in here"}100100100100
How can I capture the curl move and subsequent API response?