Using cURL as an alternate to PHP copy

My hosting site does not allow the PHP copy command from URLs, so I needed to use cURL.

Return to blog
Posted: October 8, 2019 09:58

Part of my Movie Library code uses the PHP command copy to download an image file from The Movie Database to my hosting server. Unfortunately, my hosting service prohibits copy (indirectly), as I discovered from the following error message in the log.

https:// wrapper is disabled in the server configuration by allow_url_fopen=0

Most solutions suggest editing the php.ini file to enable this, but that wasn't an option for me. Some results suggested using cURL, so after reading many solutions, I came up with a new function that directly replaces copy($src, $dest) with my own, that uses cURL.

function curlCopy($src, $dest) {
  //copy a file from another server to local via cURL
  $curl = curl_init();
  //set options
  curl_setopt_array($curl, array(
    CURLOPT_URL => $src,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_ENCODING => "",
    CURLOPT_TIMEOUT => 30,
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
    CURLOPT_CUSTOMREQUEST => "GET"
  ));
  //run it
  $response = curl_exec($curl);
  $errorNumber = curl_errno($curl);
  $errorMessage = curl_error($curl);
  curl_close($curl);
  //error check
  if ($errorNumber) {
    $status = 'curlCopy error #' . $errorNumber . ' - ' . $errorMessage;
  } else {
    $status = 'success';
    $fp = fopen($dest, 'wb');
    fputs($fp, $response);
    fclose($fp);
  }
  return $status;
}

I want to go through the code to call out some things that I wished I knew when I started.

  $curl = curl_init();

First part of any cURL call is the initialization. Pick a variable name that works for you, but almost all the ones I have read simply use $curl.

  curl_setopt_array($curl, array(
    CURLOPT_URL => $src,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_ENCODING => "",
    CURLOPT_TIMEOUT => 30,
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
    CURLOPT_CUSTOMREQUEST => "GET"
  ));

I have read so many variations on cURL options, but these are the ones that were either common to most guides or had good reasoning.

  • CURLOPT_URL is the full source URL.
  • CURLOPT_RETURNTRANSFER tells cURL that the file transfer contents will be returned via the curl_exec call.
  • CURLOPT_ENCODING tells it to accept all encoding.
  • CURLOPT_TIMEOUT set a 30 second timeout for the call to execute; should be plenty for an image copy.
  • CURLOPT_HTTP_VERSION forces HTTP 1.1 for Many Good Reasons; most articles had different but solid reasons.
  • CURLOPT_CUSTOMREQUEST setting GET as the request type.
  $response = curl_exec($curl);
  $errorNumber = curl_errno($curl);
  $errorMessage = curl_error($curl);
  curl_close($curl);

The response, in this case the JPG image file contents, are retured to $response from the curl_exec call. I also grab the cURL error number and message text, then close off the cURL call. The image file contents are now stored in $response, waiting to be saved somewhere.

  if ($errorNumber) {
    $status = 'curlCopy error #' . $errorNumber . ' - ' . $errorMessage;
  } else {
    $status = 'success';
    $fp = fopen($dest, 'wb');
    fputs($fp, $response);
    fclose($fp);
  }
  return $status;

If there is a non-0 error number, then I build an error string to be returned at the end of the function. Otherwise, I write out the image contents to the full path (with destination file name) file. wb opens the destination file for write-only, as a binary file.

Now this error return method is a little sketchy, but like all coding it was a compromise between calling a function that, so far, has worked 100% of the time. If it failed, my only plan was to log out the error and tell the user.