PHP cURL CURLOPT_PROGRESSFUNCTION - Large files cause hang? - php

I am not sure if hang is the correct term, but once the file is 100% uploaded my code after the upload code is not ran.
set_time_limit( 0 );
$fp = fopen( $zip_file, 'r' );
$curl_handler = curl_init();
curl_setopt( $curl_handler, CURLOPT_URL, 'https://upload-site/' . $zip_name . '.zip' );
curl_setopt( $curl_handler, CURLOPT_HTTPHEADER, [
'requesttoken: ' . $request_token,
'authorization: Basic ' . $basic_authorization_token,
] );
curl_setopt( $curl_handler, CURLOPT_PUT, true );
curl_setopt( $curl_handler, CURLOPT_INFILESIZE, filesize( $zip_file ) );
curl_setopt( $curl_handler, CURLOPT_INFILE, $fp );
curl_setopt( $curl_handler, CURLOPT_NOPROGRESS, false );
curl_setopt( $curl_handler, CURLOPT_PROGRESSFUNCTION, [ $this, 'updateUploadProgress' ] );
curl_setopt( $curl_handler, CURLOPT_TIMEOUT, 0 );
curl_setopt( $curl_handler, CURLINFO_HEADER_OUT, true );
$curl_retval = curl_exec( $curl_handler );
curl_close( $curl_handler );
//This code here is never ran on large file uploads.
Progress function (works)
function updateUploadProgress( $curl_handler, $download_file_size, $downloaded, $upload_file_size, $uploaded ) {
$progress = round( ( $uploaded / $upload_file_size ) * 100 );
echo 'Uploading... ' . $progress . " / 100%\n";
}
When uploading small files around 5mb everything works fine. But uploading a 500mb file after hitting 100/100 on the upload progress none of the code after curl_close() gets ran.

The question is not really a [mre], but I tried to get it to run on my local system.
(My PHP coding skills are low...)
I change the line: $curl_retval = curl_exec( $curl_handler ); to:
//$curl_retval = curl_exec( $curl_handler );
if(curl_exec($curl_handler) === false)
{
echo 'Curl error: ' . curl_error($curl_handler);
}
else
{
echo 'Operation completed without any errors';
}
After updateUploadProgress was called multiple times, I did receive next message:
Curl error: Failed to connect to localhost port 443: Connection refused
This error is correct, because I am not allowed to upload to my local system (😉).
But I do ask meself which message you (#Midger) will be receiving ...

Related

How to debug the error "Deprecated: curl_setopt():"

I have an old script that uploads PDF files via an API. I'm getting the error message:
Deprecated: curl_setopt(): The usage of the #filename API for file
uploading is deprecated. Please use the CURLFile class instead.
Here is the relevant code (I think this is all of it). The error points to the line: curl_setopt( $curl_handle, CURLOPT_POSTFIELDS, $postFields ).
//Upload the file
function uploadPdf( $api, $lead_id, $rev, $existing_files = array() ) {
if ( ! file_exists( SERVERPATH . "quotes/quote-". $this->id .".pdf" ) )
$this->createQuotePdf();
$files_array = array( array( 'entityType'=>'files', 'name'=>"quote-". $this->id .".pdf" ) );
// if ( $this->upfile && ! file_exists( SERVERPATH . "uploads/" . $upfile ) )
// $files_array[] = array( array( 'entityType'=>'files', 'name'=> $upfile ) );
foreach ( $existing_files as $file ) {
$files_array[] = (array) $file;
}
//this request gives us the URLs to upload to
$result = $api->editLead( array( 'leadId' => $lead_id, 'rev'=>'REV_IGNORE', 'lead'=> array( 'file' => $files_array ) ) );
//Upload the Quote file
$postFields = array();
$postFields['file'] = "#" . SERVERPATH . "quotes/quote-". $this->id .".pdf";
$postFields['type'] = "application/pdf";
$curl_handle = curl_init();
$file = array_pop( $result->file );
curl_setopt( $curl_handle, CURLOPT_URL, $file->uri );
curl_setopt( $curl_handle, CURLOPT_RETURNTRANSFER, true );
curl_setopt( $curl_handle, CURLOPT_POST, true );
curl_setopt( $curl_handle, CURLOPT_USERPWD, USERNAME . ":" . API_KEY );
curl_setopt( $curl_handle, CURLOPT_POSTFIELDS, $postFields );
//execute the API Call
$return = curl_exec( $curl_handle ) ;
$this->uploadUpfile($api, $lead_id);
return $return;
}
My knowledge is pretty basic. But I've tried to replace:
$postFields['file'] = "#" . SERVERPATH . "quotes/quote-". $this->id .".pdf";
$postFields['type'] = "application/pdf";
with
$postFields['file'] = curl_file_create(SERVERPATH . "quotes/quote-". $this->id .".pdf", 'application/pdf', SERVERPATH . "quotes/quote-". $this->id .".pdf");
Doing the above has got rid of the error, but the underlying problem where I can't actually open the uploaded file is still happening. So I'm wondering if I've done something wrong?
From PHP 5.5 and above you should use CURLFile to upload file, I have already posted a complete answer describing CURLFile and normal file upload, you can check that answer here.
You can use CURLFile as below, feel free to adjust the code as per your need:
//Upload file using CURLFile
function upload($target, $postFields){
$file = $postFields['file'];
$cFile = new CURLFile($file,$postFields['type'], $file);
$data = array(
'file' => $cFile,
'type' => $postFields['type'],
);
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $target);
curl_setopt($curl, CURLOPT_HEADER , true); //we need header
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); // stop verifying certificate
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true); // enable posting
curl_setopt($curl, CURLOPT_POSTFIELDS, $data); // post images
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); // if any redirection after upload
curl_setopt($curl, CURLOPT_SAFE_UPLOAD, true);
$r = curl_exec($curl);
if (curl_errno($curl)) {
$error = curl_error($curl);
print_r($error);
} else {
// check the HTTP status code of the request
$resultStatus = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if ($resultStatus != 200) {
print_r($resultStatus);
}else{
//successfull
print_r($r);
}
}
curl_close($curl);
}
As your file and filetype are in an array named $postFields, so you can call the above function as below:
upload($target, $postFields);
where $target is the link which you are calling to upload the file.

Using Google Text-To-Speech API to save speech audio

I am trying to implement methods discussed in this question to write a php function that downloads an audio file for a given string, but I can't seem to get around google's abuse protection. Results are sporadic, sometimes I get an audio file and other times it's an empty 2KB mp3 due to a response with "Our systems have detected unusual traffic from your computer network". Here is what I've got so far ( note the $file has a location in my code but for the purposes of this I've omitted it ) :
function downloadMP3( $url, $file ){
$curl = curl_init();
curl_setopt( $curl, CURLOPT_URL, $url );
curl_setopt( $curl, CURLOPT_RETURNTRANSFER, true );
curl_setopt( $curl, CURLOPT_REFERER, 'http://translate.google.com/' );
curl_setopt( $curl, CURLOPT_USERAGENT, 'stagefright/1.2 (Linux;Android 5.0)' );
$output = curl_exec( $curl );
curl_close( $curl );
if( $output === false ) {
return false;
}
$fp = fopen( $file, 'wb' );
fwrite( $fp, $output );
fclose( $fp );
return true;
}
$word = "Test";
$file = md5( $word ) . '.mp3';
if ( !file_exists( $file ) ) {
$url = 'http://translate.google.com/translate_tts?q=' . $word . '&tl=en&client=t';
downloadMP3( $url, $file );
}
Try another service, I just found one that works even better than Google Translate; Google Text-To-Speech API

PHP cURL - Get remaining time of download

I am offering my users to use remote-upload to download the content directly on my server from (for example) their own server instead of local uploads. For that I'm using cURL. And now I want to get the remaining time cURL needs to complete the download (bitrate would be fine too).
Is there a way I can return the remaining time cURL needs to finish the download via the PHP curl module or do I need to run the command-line interface and somehow put the output in a file and then read from there (since PHP blocks execution when using shell_exec() or exec())?
I'm already getting the bytes expected to download and how many curl already downloaded. This is the associated code as far:
function write_progress($ch, $original_size, $current_size, $os_up, $cs_up) {
global $anitube, $cache;
$cache->write("webupload-progress-".$anitube->input['inputname'], serialize(array("total" => $original_size, "loaded" => $current_size)));
}
ini_set('max_execution_time', '0');
$handle_file = "/tmp/file-".$anitube->generate(20).".tmp";
if(DIRECTORY_SEPARATOR == "\\") {
$handle_file = IN_DIR.$handle_file;
}
$file = fopen($handle_file, "w+");
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, urldecode(trim($anitube->input['filename'])));
curl_setopt($ch, CURLOPT_FILE, $file);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
curl_setopt($ch, CURLOPT_NOPROGRESS, false);
curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, "write_progress");
if($anitube->users['ip'] == "127.0.0.1") {
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
}
$data = curl_exec($ch);
if(curl_errno($ch) > 0) {
file_put_contents(IN_DIR."/logs/curl_errors.txt", date("d.m.Y H:i:s")." - Errno: ".curl_errno($ch)." - Error: ".curl_error($ch)." - cURL 4: ".print_r(curl_getinfo($ch), true)."\n", FILE_APPEND);
die(json_encode(array("success" => 0, "response" => $language->word('remote_file_not_available'))));
} elseif(curl_getinfo($ch, CURLINFO_HTTP_CODE) != 200) {
file_put_contents(IN_DIR."/logs/curl_errors.txt", date("d.m.Y H:i:s")." - Error: Connection denied - HTTP-Response-Code: ".curl_getinfo($ch, CURLINFO_HTTP_CODE)." - cURL 4: ".print_r(curl_getinfo($ch), true)."\n", FILE_APPEND);
die(json_encode(array("success" => 0, "response" => $language->word('remote_file_not_available'))));
}
curl_close($ch);
fclose($file);
PHP's cURL library does not appear to provide the estimated time remaining, but it is fairly trivial to calculate this from PHP using the CURLOPT_PROGRESSFUNCTION callback function. I've created a working example below. Note that if GZIP compression is enabled, the output will probably be delayed until the entire request is complete.
Example:
<?php
header( 'Content-Type: text/plain' );
//A helper function to flush output buffers.
function flush_all() {
while ( ob_get_level() ) {
ob_end_flush();
}
flush();
}
$download_start_time = null;
function write_progress( $ch, $original_size, $current_size, $os_up, $cs_up ) {
global $download_start_time;
//Get the current time.
$now = microtime( true );
//Remember the start time.
if ( ! $download_start_time ) {
$download_start_time = $now;
}
//Check if the download size is available yet.
if ( $original_size ) {
//Compute time spent transfering.
$transfer_time = $now - $download_start_time;
//Compute percent already downloaded.
$transfer_percentage = $current_size / $original_size;
//Compute estimated transfer time.
$estimated_tranfer_time = $transfer_time / $transfer_percentage;
//Compute estimated time remaining.
$estimated_time_remaining = $estimated_tranfer_time - $transfer_time;
//Output the remaining time.
var_dump( $estimated_time_remaining );
flush_all();
}
}
//Example usage.
$file = fopen( 'tmp.bin', "w+");
$ch = curl_init();
curl_setopt( $ch, CURLOPT_URL, 'https://ftp.mozilla.org/pub/mozilla.org/firefox/releases/35.0.1/win32/en-US/Firefox%20Setup%2035.0.1.exe' );
curl_setopt( $ch, CURLOPT_FILE, $file );
curl_setopt( $ch, CURLOPT_NOPROGRESS, false );
curl_setopt( $ch, CURLOPT_PROGRESSFUNCTION, 'write_progress' );
$data = curl_exec( $ch );

AWS Apache PHP works from outside but fails when tried to invoke using IP within

I have an AWS setup with Apache/PHP server on Port 80 and a REST Tomcat server on 8080.
If I try to access REST Services using IP Address A.B.C.D:8080/restapp from outside it works.
However if I try invoking from PHP code on the same box, it throws an internal error. Need your expert help in debugging this:
Checklist:
Security Profile:
8080 and 80 opened for 0.0.0.0/0
URL to be invoked: http://ec2-A-B-C-D.us-west-1.compute.amazonaws.com/myapp/ba-simple-proxy1.php?url=http://ec2-A-B-C-D.us-west-1.compute.amazonaws.com:8080/restapp/rest/user
ERROR RESPONSE:
"NetworkError: 500 Internal Server Error - http://ec2-A-B-C-D.us-west-1.compute.amazonaws.com/myapp/ba-simple-proxy1.php?url=http://ec2-A-B-C-D.us-west-1.compute.amazonaws.com:8080/restapp/rest/user"
Code Snippet from PHP - ba-simple-proxy1.php:
//print $url;
if ( !$url ) {
// Passed url not specified.
$contents = 'ERROR: url not specified';
$status = array( 'http_code' => 'ERROR' );
} else if ( !preg_match( $valid_url_regex, $url ) ) {
// Passed url doesn't match $valid_url_regex.
$contents = 'ERROR: invalid url';
$status = array( 'http_code' => 'ERROR' );
} else {
$ch = curl_init( $url );
if ( strtolower($_SERVER['REQUEST_METHOD']) == 'post' ) {
curl_setopt( $ch, CURLOPT_POST, true );
curl_setopt( $ch, CURLOPT_POSTFIELDS, $_POST );
}
if ( $_GET['send_cookies'] ) {
$cookie = array();
foreach ( $_COOKIE as $key => $value ) {
$cookie = array();
foreach ( $_COOKIE as $key => $value ) {
$cookie[] = $key . '=' . $value;
}
if ( $_GET['send_session'] ) {
$cookie[] = SID;
}
$cookie = implode( '; ', $cookie );
curl_setopt( $ch, CURLOPT_COOKIE, $cookie );
}
curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, true );
curl_setopt( $ch, CURLOPT_HEADER, true );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
curl_setopt( $ch, CURLOPT_USERAGENT, $_GET['user_agent'] ? $_GET['user_agent'] : $_SERVER['HTTP_USER_AGENT'] );
list( $header, $contents ) = preg_split( '/([\r\n][\r\n])\\1/', curl_exec( $ch ), 2 );
//print $ch;
$status = curl_getinfo( $ch );
curl_close( $ch );
}
Turns out the php_curl lib was not part of PHP5 installation. I installed it and everything works fine now.

PHP Curl File Upload Multipart Boundary

Writing an application that proxies a file upload. I'm using CURL to post the file but having a few problems. Posting to the script is ok, its posting from the script to the next server which is the problem. I keep getting this error from the server:
"the request was rejected because no multipart boundary was found"
here is my code:
$post = $_POST;
// allow for file upload proxying
if( !empty( $_FILES ) ){
// add to post data
foreach( $_FILES as $name => $upload ){
$post[ $name ] = '#' . $upload[ 'tmp_name' ] . ';type=image/png';
}
}
// init curl
$ch = curl_init( $url );
// configure options
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, true );
// post data
if( !empty( $post ) ){
curl_setopt( $ch, CURLOPT_POST, true );
curl_setopt( $ch, CURLOPT_POSTFIELDS, $post );
// for file uploads, multi-part
curl_setopt( $ch, CURLOPT_HTTPHEADER, array(
'Content-type: multipart/form-data;'
) );
}
// execute and get return value
$return = trim( curl_exec( $ch ) );
// cleanup
curl_close( $ch );
unset( $ch );
Everything I've read online suggests that this should work and also that setting the header content type is unnecessary, but when I remove the content type I get this error:
"the request doesn't contain a multipart/form-data or multipart/mixed stream, content type header is null"
any ideas? thanks in advance
Not sure exactly what the problem was, but I was working locally when I posted this. Moved the code onto a live server and the problem disappeared...

Categories