Перезапись $_POST для запросов PUT или DELETE
В PHP я хотел бы иметь доступ к PUT
и DELETE
vars глобально, похожим на то, как к GET
и POST
к ним обращаются глобально. Первоначально я рассматривал возможность добавления данных в $_PUT
и $_DELETE
соответственно в глобальном пространстве имен, но затем я понял, что данные для каждого запроса хранятся в теле сообщения, поэтому нет возможности для этого иметь более одного набора данных из POST
, PUT
или DELETE
.
Есть ли побочные эффекты перезаписи переменной $_POST
?
то есть. str_parse( file_get_contents( 'php://input' ), $_POST );
Неужели я глуп, или есть лучший способ доступа к данным PUT
и DELETE
?
Изменить, чтобы прояснить мое мышление:
Я очень хорошо знаю источник данных в $_POST
, на самом деле я упомянул об этом ранее в своем вопросе. Если на сервер отправляется запрос HTTP POST, данные хранятся в php://input
. Если на сервер отправляется запрос HTTP PUT или DELETE, данные хранятся в том же месте, что означает, что $_POST
будет пустым (поскольку данные не были POSTed
, несмотря на доступность данных.
A GET
запрос, с другой стороны, передается через строку запроса. Это позволяет одновременно передавать переменные $_POST
и $_GET
. Это не возможность одновременного прохождения переменных POST
и PUT or DELETE
.
Если я перезаписываю $_POST
из php://input
в PUT
и /DELETE
запросах, потеря данных отсутствует.
Альтернатива добавления:
global $_PUT;
global $_DELETE;
к началу функций кажется глупым, так как я могу использовать только по одному в любом случае.
Мой первый вопрос, который я действительно хочу получить, касается того, какие побочные эффекты или проблемы существуют при перезаписывании $_POST
. Я не могу быть первым, кто попробует что-то глупое:
$_POST['foo'] = 'bar';
Я просто обеспокоен тем, что если я сделаю что-то похожее, чтобы оно не сохранилось по областям.
Ответы
Ответ 1
Вы увидите, что это называется "плохой практикой" по всему Интернету, но если вы действительно понимаете, почему это "плохая практика", ну, ответы становятся нечеткими. Самая конкретная причина - так называемый сценарий "удар по автобусу" - что, если проект передается новому разработчику?
Рука, отталкивающая в сторону (вы можете оставить комментарии, в конце концов), действительно нет убедительной причины не делать это так, но опять же, нет веских оснований это тоже. Почему бы не поместить значения в ключ $_SESSION
, если вы хотите, чтобы они были глобальными? Или сделать глобальную переменную? Или сделать статический класс для доступа к значениям PUT/DELETE? Со всеми другими дополнительными подходами, я думаю, что перезапись $_POST
, в то время как это не приведет к взрыву вашего сервера, скорее всего, приведет к головной боли по дороге.
Я бросил этот маленький статический класс вместе, вы захотите проверить это, прежде чем полагаться на него. Использование:
//To check if this is a rest request:
Rest::isRest();
//To get a parameter from PUT
$put_var = Rest::put('keyname', false);
//To get a parameter from DELETE
$dele_var = Rest::delete('keyname', false);
class Rest {
static private $put = false;
static private $delete = false;
static private $is_rest = false;
function __construct() {
self::$is_rest = true;
switch ($_SERVER['REQUEST_METHOD']) {
case 'PUT':
parse_str(self::getVars(), self::$put);
break;
case 'DELETE':
parse_str(self::getVars(), self::$delete);
break;
default:
self::$is_rest = false;
}
}
private static function getVars() {
if (strlen(trim($vars = file_get_contents('php://input'))) === 0)
$vars = false;
return $vars;
}
public static function delete($key=false, $default=false) {
if (self::$is_rest !== true)
return $default;
if (is_array(self::$delete) && array_key_exists($key, self::$delete))
return self::$delete[$key];
return $default;
}
public static function put($key=false, $default=false) {
if (self::$is_rest !== true)
return $default;
if (is_array(self::$put) && array_key_exists($key, self::$put))
return self::$put[$key];
return $default;
}
public static function isRest() {
return self::$is_rest;
}
}
Ответ 2
Оставьте сообщение и получите как есть. он не должен изменяться, поскольку он предназначен только для чтения. Создайте глобальные переменные $_PUT и $_DELETE:
// globals
$_DELETE = array ();
$_PUT = array ();
switch ( $_SERVER['REQUEST_METHOD'] ) {
case !strcasecmp($_SERVER['REQUEST_METHOD'],'DELETE'):
parse_str( file_get_contents( 'php://input' ), $_DELETE );
break;
case !strcasecmp($_SERVER['REQUEST_METHOD'],'PUT'):
parse_str( file_get_contents( 'php://input' ), $_PUT );
break;
}
Не тестировалось, но вы должны получить эту идею. Несколько недель назад я искал рамки для отдыха и решил пойти с python. Перерыв (http://www.recessframework.org/) кажется многообещающим, хотя
Ответ 3
Вы не должны изменять $_POST
напрямую, так как это представляет значения, исходящие от клиента. Рассмотрите его только для чтения и внесите какие-либо изменения в пользовательскую переменную.
В качестве контроля за доступом к данным PUT и DELETE в настоящее время нет суперглобального встроенного в PHP для прямого доступа к этим данным. Поскольку данные являются файловыми данными, которые могут быть довольно большими, полезность и эффективность чтения всего содержимого файла в типичном присваивании $variable = $_PUT['file'];
сомнительна. Вместо этого его следует читать в кусках. Таким образом, использование согласуется с чтением с любого другого ресурса ввода файлов.
Подробнее о PUT здесь:
http://php.net/manual/en/features.file-upload.put-method.php
Ответ 4
Если вы создаете объект "запрос", то независимо от того, идет ли запрос через HTTP, командную строку или через веб-сокет HTML5, у вас будет единый способ доступа к данным запроса. Затем вы можете сделать объект запроса доступным в глобальной области или передать его как аргумент требуемым функциям или методам.
В идеале вы должны хранить данные, которые не зависят от запроса в статических или глобальных переменных, например. параметры, которые являются "статическими" независимо от запроса, и данными, специфичными для запроса в локальной переменной или объекте, которые могут использоваться вашей бизнес-логикой. Например, если у вас был сервер веб-сокетов, было бы проще обрабатывать несколько объектов запроса в одном PHP-процессе. Вот пример, который может помочь:
$headers = getallheaders();
$query = parse_str($_SERVER['QUERY_STRING']);
$data = file_get_contents('php://input');
if(strpos($headers['Content-Type'],'application/x-www-form-urlencoded') !== false)
{
$data = parse_str($data);
}
elseif(strpos($headers['Content-Type'],'application/json') !== false)
{
$data = json_decode($data);
}
elseif(strpos($headers['Content-Type'],'application/soap+xml') !== false)
{
$data = // parse soap
}
elseif(strpos($headers['Content-Type'],'application/xml') !== false)
{
$data = // parse xml
}
// else ...
$request = new Request($_SERVER['REQUEST_METHOD'],$data,$query);
// example business logic
$method = $request->get_request_method();
$obj = new BlogPost();
if($method == 'GET')
{
$obj->id($request->get_query('id'));
$obj->load();
}
elseif($method == 'PUT')
{
$obj->id($request->get_query('id'));
$obj->title($request->get_data('title'));
$obj->body($request->get_data('body'));
$obj->save();
}
elseif($method == 'POST')
{
$obj->title($request->get_data('title'));
$obj->body($request->get_data('body'));
$obj->save();
}
elseif($method == 'DELETE')
{
$obj->id($request->get_query('id'));
$obj->wipe();
}
Независимо от того, является ли это PUT, POST, PATCH или DELETE, в HTTP-запросе имеется только один массив данных, поэтому вашему приложению не нужен комплексный объект запроса. Объект запроса может сделать ваш контроллер (если вы используете MVC) очень просто.