Last active
July 18, 2023 20:13
-
-
Save rxnlabs/f9086204b035c1f92095dabfc53aa181 to your computer and use it in GitHub Desktop.
WordPress - Upload files to remote API using WP_Http / wp_remote_post + cURL + fsockopen + CurlFile
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
$url = 'https://insert-domain-here.com/api-endpoint'; | |
// The file is stored on your system/host | |
$path_to_uploaded_file = '/full-path-to-file/picture.jpg'; | |
$form_fields = [ 'first_name' => 'Foo', 'last_name' => 'Bar' ]; | |
if ( file_exists( $path_to_uploaded_file ) ) { | |
$form_fields['profile_picture'] = new CurlFile( $path_to_uploaded_file ); | |
} | |
/* | |
Use an anonymous function and pass the local variable that we want to post to that function since | |
the http_api_curl hook does not pass the data that we actually want to POST with the hook | |
If $form_fields is global variable, no need to pass it to the anonymous function using the 'use' keyword since 'use' is great for local scope variable | |
*/ | |
$file_upload_request = function( $handle_or_parameters, $request = '', $url = '' ) use ( $form_fields ) { | |
updateWPHTTPRequest( $handle_or_parameters, $form_fields ); | |
}; | |
// handle cURL requests if we have cURL installed | |
add_action( 'http_api_curl', $file_upload_request, 10 ); | |
// handle fsockopen requests if we don't have cURL installed | |
add_action( 'requests-fsockopen.before_send', $file_upload_request, 10, 3 ); | |
$request = wp_remote_post( $url, [ | |
'body' => $form_fields, | |
'headers' => [ | |
'content-type' => 'multipart/form-data', // set Content-type: multipart/form-data header for file upload | |
] | |
] ); | |
$body = wp_remote_retrieve_body( $request ); | |
$response_code = wp_remote_retrieve_response_code( $request ); | |
// Remove actions so we don't modify any other WP_Http requests | |
remove_action( 'http_api_curl', $file_upload_request ); | |
remove_action( 'requests-fsockopen.before_send', $file_upload_request ); | |
// Let's upload another photo cause a possum had just attacked me in that photo. I want a cooler photo. | |
$url2 = 'https://insert-domain-here.com/api-endpoint2'; | |
$path_to_uploaded_file2 = '/full-path-to-file/picture2.jpg'; | |
$form_fields2 = [ 'first_name' => 'Bar', 'last_name' => 'Foo' ]; | |
if ( file_exists( $path_to_uploaded_file2 ) ) { | |
$form_fields['profile_picture'] = new CurlFile( $path_to_uploaded_file2 ); | |
} | |
$file_upload_request2 = function( $handle_or_parameters, $request = '', $url = '' ) use ( $form_fields2 ) { | |
updateWPHTTPRequest( $handle_or_parameters, $form_fields2 ); | |
}; | |
$request2 = wp_remote_post( $url2, [ | |
'body' => $form_fields2, | |
'headers' => [ | |
'content-type' => 'multipart/form-data', | |
] | |
] ); | |
$body2 = wp_remote_retrieve_body( $request2 ); | |
$response_code2 = wp_remote_retrieve_response_code( $request2 ); | |
remove_action( 'http_api_curl', $file_upload_request2 ); | |
remove_action( 'requests-fsockopen.before_send', $file_upload_request2 ); | |
/* | |
. | |
.:;:. | |
.:;;;;;:. | |
;;;;; | |
;;;;; | |
;;;;; | |
;;;;; | |
;:;;; | |
You saw what we had to do above right?? We have to use a local variable of $form_fields and $form_fields2 to pass to our hook | |
so we can modify the wp_remote_post request to use the form fields in the way that we want. | |
You'll either have to use global variables or localled scoped variables to pass the array or form fields that we want to post | |
to the remote API | |
*/ | |
/** | |
* Update the WP cURL and fsockopen requests to make them work with file uploads. | |
* @param resource|array $handle_or_parameters cURL handle or fsockopen parameters. This is passed by reference | |
* @param array $form_body_arguments Form data to POST to the remote service | |
* @return void | |
*/ | |
function updateWPHTTPRequest( &$handle_or_parameters, $form_body_arguments ) { | |
if ( function_exists( 'curl_init' ) && function_exists( 'curl_exec' ) ) { | |
foreach ( $form_body_arguments as $value ) { | |
// Only do this if we are using PHP 5.5+ CURLFile file to upload a file | |
if ( 'object' === gettype( $value ) && $value instanceof CURLFile ) { | |
/* | |
Use the request body as an array to force cURL make a requests using 'multipart/form-data' | |
as the Content-type header instead of WP's default habit of converting the request to | |
a string using http_build_query function | |
*/ | |
curl_setopt( $handle_or_parameters, CURLOPT_POSTFIELDS, $form_body_arguments ); | |
break; | |
} | |
} | |
} elseif ( function_exists( 'fsockopen' ) ) { | |
// UNTESTED SINCE I HAVE cURL INSTALLED AND CANNOT TEST THIS | |
$form_fields = []; | |
$form_files = []; | |
foreach ( $form_body_arguments as $name => $value ) { | |
if ( file_exists( $value ) ) { | |
// Not great for large files since it dumps into memory but works well for small files | |
$form_files[$name] = file_get_contents( $value ); | |
} else { | |
$form_fields[$name] = $value; | |
} | |
} | |
/** | |
* Convert form fields arrays to a string that fsockopen requests can understand | |
* | |
* @see https://gist.github.com/maxivak/18fcac476a2f4ea02e5f80b303811d5f | |
*/ | |
function build_data_files( $boundary, $fields, $files ){ | |
$data = ''; | |
$eol = "\r\n"; | |
$delimiter = '-------------' . $boundary; | |
foreach ( $fields as $name => $content ) { | |
$data .= "--" . $delimiter . $eol | |
. 'Content-Disposition: form-data; name="' . $name . "\"".$eol.$eol | |
. $content . $eol; | |
} | |
foreach ( $files as $name => $content ) { | |
$data .= "--" . $delimiter . $eol | |
. 'Content-Disposition: form-data; name="' . $name . '"; filename="' . $name . '"' . $eol | |
//. 'Content-Type: image/png'.$eol | |
. 'Content-Transfer-Encoding: binary'.$eol | |
; | |
$data .= $eol; | |
$data .= $content . $eol; | |
} | |
$data .= "--" . $delimiter . "--".$eol; | |
return $data; | |
} | |
$boundary = uniqid(); | |
$handle_or_parameters = build_data_files( $boundary, $form_fields, $form_files ); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment