Мне было приказано использовать метод php://input
вместо того, чтобы $_POST
взаимодействовать с Ajax-запросами из JQuery. То, что я не понимаю, это преимущества использования этого по сравнению с глобальным методом $_POST
или $_GET
.
Мне было приказано использовать метод php://input
вместо того, чтобы $_POST
взаимодействовать с Ajax-запросами из JQuery. То, что я не понимаю, это преимущества использования этого по сравнению с глобальным методом $_POST
или $_GET
.
Ответы:
Причина в том, что php://input
возвращает все необработанные данные после HTTP-заголовков запроса, независимо от типа контента.
PHP суперглобальный $_POST
, только предполагается, что обернуть данные, которые либо
application/x-www-form-urlencoded
(стандартный тип контента для простых форм-постов) илиmultipart/form-data
(в основном используется для загрузки файлов)Это потому, что это единственные типы контента, которые должны поддерживаться пользовательскими агентами. . Таким образом, сервер и PHP традиционно не ожидают получения какого-либо другого типа контента (что не означает, что они не могли).
Итак, если вы просто поместите старый добрый HTML form
, запрос будет выглядеть примерно так:
POST /page.php HTTP/1.1
key1=value1&key2=value2&key3=value3
Но если вы много работаете с Ajax, эта проба также включает в себя обмен более сложными данными с типами (string, int, bool) и структурами (массивами, объектами), поэтому в большинстве случаев JSON является лучшим выбором. Но запрос с JSON-полезной нагрузкой будет выглядеть примерно так:
POST /page.php HTTP/1.1
{"key1":"value1","key2":"value2","key3":"value3"}
Теперь контент будет application/json
(или, по крайней мере, ни один из вышеупомянутых), поэтому PHP $_POST
-wrapper не знает, как с этим справиться (пока).
Данные все еще там, вы просто не можете получить к ним доступ через обертку. Так что вам нужно получить его самостоятельно в необработанном формате file_get_contents('php://input')
( если он не multipart/form-data
закодирован ).
Это также, как вы бы получили доступ к XML-данным или любому другому нестандартному типу контента.
application/json
как действительный источник данных для $_POST
массива. И есть даже опубликованные запросы специально для этой поддержки.
php://input
может дать вам необработанные байты данных. Это полезно, если данные POST представляют собой структуру в кодировке JSON, что часто имеет место для запроса AJAX POST.
Вот функция для этого:
/**
* Returns the JSON encoded POST data, if any, as an object.
*
* @return Object|null
*/
private function retrieveJsonPostData()
{
// get the raw POST data
$rawData = file_get_contents("php://input");
// this returns null if not valid json
return json_decode($rawData);
}
$_POST
Массив является более полезным , когда вы обработки данных ключ-значение из формы, представленной традиционным POST. Это работает только в том случае, если POST-данные обычно имеют распознанный формат application/x-www-form-urlencoded
(подробнее см. Http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4 ).
true
в качестве второго параметра json_decode
, он вернет ассоциативный массив.
Если данные поста искажены, $ _POST ничего не будет содержать. Тем не менее, php: // input будет иметь некорректную строку.
Например, есть некоторые ajax-приложения, которые не формируют правильную последовательность ключ-значение поста для загрузки файла, а просто выгружают весь файл как данные поста, без имен переменных или чего-либо еще. $ _POST будет пустым, $ _FILES также пустым, а вход php: // будет содержать точный файл, записанный в виде строки.
PHP не был разработан для того, чтобы явно предоставлять вам чистый интерфейс типа REST (GET, POST, PUT, PATCH, DELETE) для обработки HTTP-запросов .
Однако $_POST
, $_GET
и $_FILES
Суперглобальные , а функция filter_input_array()
очень полезны для нужд среднего человека / непрофессионала.
Скрытое преимущество номер один $_POST
(и $_GET
) заключается в том, что ваши входные данные автоматически кодируются PHP . Вы даже не задумываетесь об этом, особенно для параметров строки запроса в стандартном запросе GET.
При этом, когда вы продвигаетесь в своих знаниях по программированию и хотите использовать XmlHttpRequest
объект JavaScript (для некоторых jQuery), вы видите ограничение этой схемы.
$_POST
ограничивает вас использованием двух типов медиа в Content-Type
заголовке HTTP :
application/x-www-form-urlencoded
, иmultipart/form-data
Таким образом, если вы хотите отправить значения данных в PHP на сервере и показать их в $_POST
суперглобальном коде , то вы должны urlencode их на стороне клиента и отправить эти данные в виде пар ключ / значение - неудобный шаг для новичков (особенно при попытке выяснить, требуются ли разные части URL-адреса для разных форм кодирования: обычный, необработанный и т. д.).
Для всех пользователей jQuery этот $.ajax()
метод преобразует ваш JSON в пары ключ / значение, закодированные в URL, перед их передачей на сервер. Вы можете изменить это поведение, установив processData: false
. Просто прочитайте документацию $ .ajax () и не забудьте отправить правильный тип носителя в заголовке Content-Type.
Как правило, если вы выполняете обычные синхронные (когда перерисовывается вся страница) HTTP-запросы с HTML-формой, пользовательский агент (веб-браузер) будет кодировать данные вашей формы для вас. Если вы хотите выполнять асинхронные HTTP-запросы с использованием XmlHttpRequest
объекта, вы должны сформировать строку с кодировкой urlen и отправить ее, если хотите, чтобы эти данные отображались в $_POST
суперглобальном элементе .
Преобразование из массива или объекта JavaScript в строку с кодировкой urlen беспокоит многих разработчиков (даже с такими новыми API, как Form Data ). Они бы предпочли просто отправить JSON, и для клиентского кода это было бы более эффективно .
Помните (подмигивание, подмигивание), обычный веб-разработчик не учится использовать XmlHttpRequest
объект напрямую, глобальные функции, строковые функции, функции массива и регулярные выражения, такие как вы и я ;-). Урленкодинг для них - это кошмар. ;-)
Отсутствие в PHP интуитивной обработки XML и JSON отвлекает многих людей. Вы могли бы подумать, что это будет частью PHP сейчас (вздох).
XML, JSON и YAML имеют типы мультимедиа, которые можно поместить в Content-Type
заголовок HTTP .
Посмотрите, сколько медиа-типов (ранее MIME-типов) определены IANA.
Посмотрите, сколько там HTTP-заголовков .
Использование php://input
потока позволяет вам обойти уровень абстракции для сидения / удерживания ребенка, который PHP навязал миру. :-) С большой властью приходит большая ответственность!
Теперь, прежде чем иметь дело со значениями потоковых данных php://input
, вы должны / должны сделать несколько вещей.
Ах, ха! Да, вы можете захотеть, чтобы поток данных, отправляемый в ваше приложение, был в кодировке UTF-8, но как узнать, так ли это?
php://input
.Собираетесь ли вы пытаться обрабатывать потоковые данные, не зная, сколько их сначала? Это ужасная идея . Вы не можете полагаться исключительно на Content-Length
заголовок HTTP для указания размера входного потока, поскольку он может быть подделан.
Вам понадобится:
Собираетесь ли вы попытаться преобразовать потоковые данные в UTF-8, не зная текущей кодировки потока? Как? Фильтр потока iconv ( пример фильтра потока iconv ), кажется, хочет начальную и конечную кодировку, как это.
'convert.iconv.ISO-8859-1/UTF-8'
Таким образом, если вы добросовестны, вам понадобится:
( Обновление : 'convert.iconv.UTF-8/UTF-8'
все будет принудительно переведено в UTF-8, но вам все равно придется учитывать символы, которые библиотека iconv может не знать, как переводить. Другими словами, вам нужно как-то определить, какое действие предпринять, когда символ не может быть переведен : 1) Вставьте фиктивный символ, 2) Fail / throw и исключения).
Вы не можете полагаться исключительно на Content-Encoding
заголовок HTTP , так как это может указывать на что-то вроде сжатия, как показано ниже. Это не то, что вы хотите принять решение в отношении iconv.
Content-Encoding: gzip
Часть I: HTTP-запрос, связанный
Часть II: Потоковые данные, связанные
Часть III: Тип данных, связанных
(Помните, что данные все еще могут быть строкой в кодировке URL, которую затем необходимо проанализировать и декодировать URL).
Часть IV: Значение данных, связанных
Фильтровать входные данные.
Проверьте входные данные.
$_POST
Суперглобальный, наряду с php.ini настройки для ограничения на вход, проще для обывателя. Однако работа с кодировкой символов намного более интуитивна и эффективна при использовании потоков, потому что нет необходимости циклически перебирать суперглобальные переменные (или вообще массивы), чтобы проверять входные значения для правильного кодирования.
Поэтому я написал функцию, которая будет получать данные POST из потока ввода php: // .
Таким образом, проблема здесь заключалась в том, чтобы переключиться на метод запроса PUT, DELETE OR PATCH и по-прежнему получать данные почты, отправленные с этим запросом.
Я делюсь этим, может быть, для кого-то с похожим вызовом. Приведенная ниже функция - это то, что я придумал, и она работает. Я надеюсь, что это помогает!
/**
* @method Post getPostData
* @return array
*
* Convert Content-Disposition to a post data
*/
function getPostData() : array
{
// @var string $input
$input = file_get_contents('php://input');
// continue if $_POST is empty
if (strlen($input) > 0 && count($_POST) == 0 || count($_POST) > 0) :
$postsize = "---".sha1(strlen($input))."---";
preg_match_all('/([-]{2,})([^\s]+)[\n|\s]{0,}/', $input, $match);
// update input
if (count($match) > 0) $input = preg_replace('/([-]{2,})([^\s]+)[\n|\s]{0,}/', '', $input);
// extract the content-disposition
preg_match_all("/(Content-Disposition: form-data; name=)+(.*)/m", $input, $matches);
// let's get the keys
if (count($matches) > 0 && count($matches[0]) > 0)
{
$keys = $matches[2];
foreach ($keys as $index => $key) :
$key = trim($key);
$key = preg_replace('/^["]/','',$key);
$key = preg_replace('/["]$/','',$key);
$key = preg_replace('/[\s]/','',$key);
$keys[$index] = $key;
endforeach;
$input = preg_replace("/(Content-Disposition: form-data; name=)+(.*)/m", $postsize, $input);
$input = preg_replace("/(Content-Length: )+([^\n]+)/im", '', $input);
// now let's get key value
$inputArr = explode($postsize, $input);
// @var array $values
$values = [];
foreach ($inputArr as $index => $val) :
$val = preg_replace('/[\n]/','',$val);
if (preg_match('/[\S]/', $val)) $values[$index] = trim($val);
endforeach;
// now combine the key to the values
$post = [];
// @var array $value
$value = [];
// update value
foreach ($values as $i => $val) $value[] = $val;
// push to post
foreach ($keys as $x => $key) $post[$key] = isset($value[$x]) ? $value[$x] : '';
if (is_array($post)) :
$newPost = [];
foreach ($post as $key => $val) :
if (preg_match('/[\[]/', $key)) :
$k = substr($key, 0, strpos($key, '['));
$child = substr($key, strpos($key, '['));
$child = preg_replace('/[\[|\]]/','', $child);
$newPost[$k][$child] = $val;
else:
$newPost[$key] = $val;
endif;
endforeach;
$_POST = count($newPost) > 0 ? $newPost : $post;
endif;
}
endif;
// return post array
return $_POST;
}
Простой пример того, как его использовать
<?php
if(!isset($_POST) || empty($_POST)) {
?>
<form name="form1" method="post" action="">
<input type="text" name="textfield"><br />
<input type="submit" name="Submit" value="submit">
</form>
<?php
} else {
$example = file_get_contents("php://input");
echo $example; }
?>