Перезапись $ _POST для запросов PUT или DELETE - PullRequest
14 голосов
/ 07 июня 2011

В 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';

Я просто обеспокоен тем, что, если я сделаю что-то похожее, это может не сохраниться во всех областях.

Ответы [ 4 ]

15 голосов
/ 07 июня 2011

Вы увидите, что это называется "плохой практикой" во всем Интернете, но если вы действительно поймете , почему это "плохая практика", ну, ответы получаются нечеткими.Наиболее конкретная причина - сценарий «попадания в автобус», о котором так часто говорят - что, если проект будет передан новому разработчику?

Рука отжимается в сторону (вы можете оставить комментарии, в конце концов), тамна самом деле это не убедительная причина , а не , чтобы делать это таким образом, но опять же, нет и веской причины к делать это.Почему бы не поместить значения в ключ $_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;
    }
}
4 голосов
/ 07 июня 2011

Оставьте сообщение и получите как есть.это не должно быть изменено, поскольку это только для чтения.Создайте глобальные переменные $ _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;
}

Не проверено, но вы должны понять это.Я сам несколько недель назад занимался поиском фреймворка для отдыха и решил поехать с питоном.Перерыв (http://www.recessframework.org/) звучит многообещающе, хотя

3 голосов
/ 07 июня 2011

Вы не должны изменять $_POST напрямую, поскольку это представляет значения, поступающие от клиента. Считайте, что это только для чтения, и внесите любые изменения в пользовательскую переменную.

Что касается доступа к данным PUT и DELETE, в настоящее время в PHP нет встроенного суперглобального элемента для прямого доступа к этим данным. Поскольку данные являются данными файла, которые могут быть довольно большими, полезность и эффективность чтения всего содержимого файла в типичном операторе присваивания $variable = $_PUT['file']; вызывает сомнения. Вместо этого это должно быть прочитано кусками. Таким образом, использование согласуется с чтением из любого другого ресурса ввода файлов.

Подробнее о PUT здесь:

http://php.net/manual/en/features.file-upload.put-method.php

0 голосов
/ 26 января 2015

Если вы создаете объект «запрос», то независимо от того, поступает ли запрос по 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-запросе содержится только одна часть данных, поэтому вашему приложению не требуется сложный объект $ request. Объект запроса может сделать ваш контроллер (если вы используете MVC) очень простым.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...