Экранирование символа CURL @ с помощью PHP - PullRequest
10 голосов
/ 15 марта 2009

Я пишу php-приложение, которое отправляет через данные curl подписку на список рассылки iContact. Однако я получаю сообщение об ошибке неверного адреса электронной почты. Я думаю, что это может быть связано с тем, что я экранирую символ @, поэтому он выглядит как% 40 вместо @. Также, согласно документации php для curl_setopt с CURLOPT_POSTFIELDS:

полные данные для публикации в HTTP «ПОЧТА» операция. Чтобы опубликовать файл, добавьте @ к имени файла и используйте полный путь.

Итак, есть ли способ пропустить символ @ как данные поста через curl в php, не запуская его сначала через urlencode?

Ответы [ 6 ]

13 голосов
/ 15 марта 2009

Используйте http_build_query() в вашем массиве данных, прежде чем передавать его в curl_setopt(), что приведет к отправке формы как application/x-www-form-encoded вместо multipart/form-data (и, таким образом, не интерпретируется).

Кроме того, почему вы действительно заботитесь о @ в адресе электронной почты? Это имеет значение, только если @ является первым символом, а не где-то посередине.

5 голосов
/ 04 февраля 2012

После поиска в руководстве по PHP curl, я обнаружил, что нет никакой информации, чтобы экранировать первое «@», если поле записи является строкой, а не файлом, если публикация с кодированием multipart / form-data.

То, как я обошел эту проблему, это префикс пробела в начале текста. В то время как наш бэкэнд API уберет пробелы, он сможет удалить пробел и восстановить исходный текст. Я не знаю, погода Twitter API будет обрезать пробелы при вводе пользователем.

Если это так, этот обходной путь также работает для вас.

Если кто-нибудь нашел способ избежать первого '@' при использовании PHP curl с кодированием multipart / form-data, пожалуйста, сообщите нам.

4 голосов
/ 05 июня 2014

Это решение true , которое может поддерживать как строки , содержащие @, так и файлы .

Решение для PHP 5.6 или более поздней версии:

  • Используйте CURLFile вместо @.

Решение для PHP 5.5 или новее:

  • Включить CURLOPT_SAFE_UPLOAD.
  • Используйте CURLFile вместо @.

Решение для PHP 5.3 или новее:

  • Соберите собственное тело из нескольких частей.
  • Изменить заголовок Content-Type самостоятельно.

Вам поможет следующий фрагмент: D

<?php

/**
 * For safe multipart POST request for PHP5.3 ~ PHP 5.4.
 * 
 * @param resource $ch cURL resource
 * @param array $assoc "name => value"
 * @param array $files "name => path"
 * @return bool
 */
function curl_custom_postfields($ch, array $assoc = array(), array $files = array()) {

    // invalid characters for "name" and "filename"
    static $disallow = array("\0", "\"", "\r", "\n");

    // initialize body
    $body = array();

    // build normal parameters
    foreach ($assoc as $k => $v) {
        $k = str_replace($disallow, "_", $k);
        $body[] = implode("\r\n", array(
            "Content-Disposition: form-data; name=\"{$k}\"",
            "",
            filter_var($v), 
        ));
    }

    // build file parameters
    foreach ($files as $k => $v) {
        switch (true) {
            case false === $v = realpath(filter_var($v)):
            case !is_file($v):
            case !is_readable($v):
                continue; // or return false, throw new InvalidArgumentException
        }
        $data = file_get_contents($v);
        $v = call_user_func("end", explode(DIRECTORY_SEPARATOR, $v));
        list($k, $v) = str_replace($disallow, "_", array($k, $v));
        $body[] = implode("\r\n", array(
            "Content-Disposition: form-data; name=\"{$k}\"; filename=\"{$v}\"",
            "Content-Type: application/octet-stream",
            "",
            $data,
        ));
    }

    // generate safe boundary 
    do {
        $boundary = "---------------------" . md5(mt_rand() . microtime());
    } while (preg_grep("/{$boundary}/", $body));

    // add boundary for each parameters
    array_walk($body, function (&$part) use ($boundary) {
        $part = "--{$boundary}\r\n{$part}";
    });

    // add final boundary
    $body[] = "--{$boundary}--";
    $body[] = "";

    // set options
    return curl_setopt_array($ch, array(
        CURLOPT_POST       => true,
        CURLOPT_POSTFIELDS => implode("\r\n", $body),
        CURLOPT_HTTPHEADER => array(
            "Expect: 100-continue",
            "Content-Type: multipart/form-data; boundary={$boundary}", // change Content-Type
        ),
    ));

}

?>
4 голосов
/ 09 декабря 2011

Я столкнулся с той же проблемой, но с самой curl, а не с PHP curl.

При использовании опции поля curl '-F' начальный символ @ не будет отправляться в POST, а вместо этого будет указывать curl отправлять имя файла, которое сразу следует за символом, как часть POST.

К счастью, curl предлагает другую опцию '--form-string', которая ведет себя так же, как и -F, за исключением того, что опция 'form-string' не анализируется.

Например, если вы хотите использовать curl для POST field1 со значением «@value» и file1 с файлом «testfile.txt», вы можете сделать это следующим образом:

curl "http://www.url.com" --form-string "field1=@value" -F "file1=@testfile.txt"
1 голос
/ 20 марта 2014

@ PatricDaryll ответ правильный, но мне нужно было провести небольшое исследование, чтобы понять, где использовать эту http_build_query функцию.

Чтобы уточнить и обобщить, вместо того, чтобы делать:

     curl_setopt($ch, CURLOPT_POSTFIELDS, $array);

Вы будете использовать:

     curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($array));

Простой, но запутанный ... curl достаточно умен, чтобы понять, дали ли вы ему строку или массив.

0 голосов
/ 11 октября 2013

Для того, чтобы экранировать знак @ в нефайловых данных, вам нужно сделать следующее. Добавить текстовую строку с символом NULL

$postfields = array(
    'upload_file' => '@file_to_upload.png',
    'upload_text' => sprintf("\0%s", '@text_to_upload')
);

$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, 'http://example.com/upload-test');
curl_setopt($curl, CURLOPT_POSTFIELDS, $postfields);
curl_exec($curl);
curl_close($curl);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...