PHP cURL, запись в файл - PullRequest
       3

PHP cURL, запись в файл

14 голосов
/ 01 ноября 2011

Я хочу попробовать подключиться к удаленному файлу и записать вывод оттуда в локальный файл, это моя функция:

function get_remote_file_to_cache()
{

$the_site="http://facebook.com";

    $curl = curl_init();
    $fp = fopen("cache/temp_file.txt", "w");
    curl_setopt ($curl, CURLOPT_URL, $the_site);
    curl_setopt($curl, CURLOPT_FILE, $fp);

    curl_setopt($curl,  CURLOPT_RETURNTRANSFER, TRUE);


    curl_exec ($curl);



    $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
    if($httpCode == 404) {
        touch('cache/404_err.txt');
    }else
    {

    touch('cache/'.rand(0, 99999).'--all_good.txt');
    }


    curl_close ($curl);
}

Создает два файла в каталоге «cache», нопроблема в том, что он не записывает данные в «temp_file.txt», почему это так?

Спасибо!
R

Ответы [ 5 ]

25 голосов
/ 18 июня 2014

На самом деле, использование fwrite частично true.Чтобы избежать проблем переполнения памяти с большими файлами (превышен максимальный предел памяти PHP), вам необходимо настроить функцию обратного вызова для записи в файл.

ПРИМЕЧАНИЕ: Я бы порекомендовал создать класс, специально предназначенный для загрузки файлов, файловых дескрипторов и т. Д., А не КОГДА-ЛИБО с использованием глобальной переменной, но для целей этого примера ниже показано, как запустить и запустить систему.

Итак, сделайте следующее:

# setup a global file pointer
$GlobalFileHandle = null;

function saveRemoteFile($url, $filename) {
  global $GlobalFileHandle;

  set_time_limit(0);

  # Open the file for writing...
  $GlobalFileHandle = fopen($filename, 'w+');

  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $url);
  curl_setopt($ch, CURLOPT_FILE, $GlobalFileHandle);
  curl_setopt($ch, CURLOPT_HEADER, 0);
  curl_setopt($ch, CURLOPT_USERAGENT, "MY+USER+AGENT"); //Make this valid if possible
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
  curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); # optional
  curl_setopt($ch, CURLOPT_TIMEOUT, -1); # optional: -1 = unlimited, 3600 = 1 hour
  curl_setopt($ch, CURLOPT_VERBOSE, false); # Set to true to see all the innards

  # Only if you need to bypass SSL certificate validation
  curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
  curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

  # Assign a callback function to the CURL Write-Function
  curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'curlWriteFile');

  # Exceute the download - note we DO NOT put the result into a variable!
  curl_exec($ch);

  # Close CURL
  curl_close($ch);

  # Close the file pointer
  fclose($GlobalFileHandle);
}

function curlWriteFile($cp, $data) {
  global $GlobalFileHandle;
  $len = fwrite($GlobalFileHandle, $data);
  return $len;
}

Вы также можете создать обратный вызов прогресса, чтобы показать, насколько / насколько быстро вы скачиваете, однако это еще один пример, поскольку это может быть сложно при выводе наCLI.

По сути, это будет принимать каждый блок загруженных данных и немедленно выгружать их в файл, а не загружать файл ENTIRE в память.

Многоебезопасный способ сделать это!Конечно, вы должны убедиться, что URL правильный (преобразовать пробелы в% 20 и т. Д.) И что локальный файл доступен для записи.

Приветствия, Джеймс.

16 голосов
/ 19 февраля 2015

Попробуем отправить запрос GET на http://facebook.com:

$ curl -v http://facebook.com
* Rebuilt URL to: http://facebook.com/
* Hostname was NOT found in DNS cache
*   Trying 69.171.230.5...
* Connected to facebook.com (69.171.230.5) port 80 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.35.0
> Host: facebook.com
> Accept: */*
> 
< HTTP/1.1 302 Found
< Location: https://facebook.com/
< Vary: Accept-Encoding
< Content-Type: text/html
< Date: Thu, 03 Sep 2015 16:26:34 GMT
< Connection: keep-alive
< Content-Length: 0
< 
* Connection #0 to host facebook.com left intact

Что случилось? Похоже, что Facebook перенаправил нас с http://facebook.com на безопасный https://facebook.com/. Обратите внимание, что длина тела ответа:

Content-Length: 0

Это означает, что нулевые байты будут записаны в xxxx--all_good.txt. Вот почему файл остается пустым.

Ваше решение абсолютно правильно:

$fp = fopen('file.txt', 'w');
curl_setopt($handle, CURLOPT_FILE, $fp);
curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);

Все, что вам нужно сделать, это изменить URL-адрес на https://facebook.com/.

Относительно других ответов:

  • @ JonGauthier: Нет, нет необходимости использовать fwrite() после curl_exec()
  • @ doublehelix: Нет, вам не нужно CURLOPT_WRITEFUNCTION для такой простой операции, которая копирует содержимое в файл.
  • @ ScottSaunders: touch() создает пустой файл, если он не существует. Я думаю, что это было намерение ОП.

Серьезно, три ответа и каждый из них недействителен?

9 голосов
/ 01 ноября 2011

Вам необходимо явно записать в файл, используя fwrite, передав ему дескриптор файла, который вы создали ранее:

if ( $httpCode == 404 ) {
    ...
} else {
    $contents = curl_exec($curl);
    fwrite($fp, $contents);
}

curl_close($curl);
fclose($fp);
2 голосов
/ 01 ноября 2011

Функция touch() ничего не делает с содержимым файла. Он просто обновляет время модификации. Посмотрите на file_put_contents() function.

0 голосов
/ 10 июня 2019

Чтобы избежать проблем с утечкой памяти:

Я тоже столкнулся с этой проблемой. Это действительно глупо, но решение состоит в том, чтобы установить CURLOPT_RETURNTRANSFER перед CURLOPT_FILE!

кажется, что CURLOPT_FILE зависит от CURLOPT_RETURNTRANSFER.

$curl = curl_init();
$fp = fopen("cache/temp_file.txt", "w+");
curl_setopt($curl,  CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_FILE, $fp);
curl_setopt($curl, CURLOPT_URL, $url);
curl_exec ($curl);
curl_close($curl);
fclose($fp);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...