Экранирование символа CURL @с помощью PHP

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

Полные данные для публикации в HTTP Операция "POST". Чтобы опубликовать файл, добавьте имя файла с помощью @и используйте полный путь.

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

Ответ 1

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

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

Ответ 2

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

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

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

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

Ответ 3

Я столкнулся с одной и той же проблемой, хотя и с завитом, а не с завихрением PHP.

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

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

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

curl "http://www.url.com" --form-string "[email protected]" -F "[email protected]"

Ответ 4

Это решение 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
        ),
    ));

}

?>

Ответ 5

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

Чтобы уточнить и обобщить, вместо выполнения:

     curl_setopt($ch, CURLOPT_POSTFIELDS, $array);

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

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

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

Ответ 6

Чтобы избежать знака @в данных, отличных от файла, вам необходимо сделать следующее. Подготовьте текстовую строку символом 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);