В PHP я хотел бы иметь доступ к глобальным сетям PUT
и DELETE
во всем мире, подобным тому, как глобальные 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
несмотря на доступность данных.
С другой стороны, запрос GET
передается через строку запроса. Это позволяет одновременно передавать переменные $_POST
и $_GET
. Нельзя одновременно передавать переменные POST
и PUT or DELETE
.
Если я перезаписываю $_POST
из запросов php://input
на запросы PUT
и DELETE
, потери данных нет.
Альтернатива добавления:
global $_PUT; global $_DELETE;
к началу функций кажется глупым, так как я могу использовать только одно за раз.
Мой первый вопрос, на который я действительно хочу ответить, касается того, какие побочные эффекты или проблемы существуют при перезаписывании $_POST
. Я не могу быть первым человеком, который может попробовать что-то глупое:
$_POST['foo'] = 'bar';
Меня просто беспокоит, что если я сделаю что-нибудь подобное, это может не сохраниться по всем областям.
Вы увидите, что это называется «плохая практика» по всему Интернету, но если вы действительно понимаете, почему это «плохая практика», ну, ответы становятся нечеткими. Самая конкретная причина – сценарий «удар по автобусу», о котором так часто говорили – что, если проект передается новому разработчику?
Рука, отталкивающая в сторону (вы можете оставить комментарии, в конце концов), действительно нет веской причины не делать этого так, но опять же, нет веских оснований для этого. Почему бы не поместить значения в ключ $_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; } }
Оставьте сообщение и получите как есть. он не должен изменяться, поскольку он предназначен только для чтения. Создайте глобальные переменные $ _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. Recess ( http://www.recessframework.org/ ) звучит многообещающе, хотя
Вы не должны напрямую изменять $_POST
поскольку это представляет значения, поступающие от клиента. Учитывайте его только для чтения и делайте какие-либо изменения в пользовательской переменной.
В качестве контроля за доступом к данным PUT и DELETE в настоящее время нет суперглобального встроенного в PHP для прямого доступа к этим данным. Поскольку данные являются файловыми данными, которые могут быть довольно большими, полезность и эффективность чтения всего содержимого файла в типичной $variable = $_PUT['file'];
присваивания $variable = $_PUT['file'];
вызывает сомнения. Вместо этого его следует читать в кусках. Таким образом, использование согласуется с чтением из любого другого входного ресурса файла.
Подробнее о PUT здесь:
http://php.net/manual/en/features.file-upload.put-method.php
Если вы создаете объект «запрос», то независимо от того, идет ли запрос по 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) очень простым.