Obsługa argumentów PUT / DELETE w PHP

84

Pracuję nad moją biblioteką klienta REST dla CodeIgniter i staram się ustalić, jak wysyłać argumenty PUT i DELETE w PHP.

W kilku miejscach widziałem ludzi korzystających z opcji:

$this->option(CURLOPT_PUT, TRUE);
$this->option(CURLOPT_POSTFIELDS, $params);

Irytujące wydaje się, że to nic nie daje. Czy to właściwy sposób ustawiania parametrów PUT?

Jeśli tak, jak ustawić parametry DELETE?

$ this-> option () jest częścią mojej biblioteki, po prostu buduje tablicę stałych CURLOPT_XX i wysyła je do curl_setopt_array (), gdy zbudowane żądanie cURL jest wykonywane.

Próbuję odczytać parametry PUT i DELETE przy użyciu następującego kodu:

        case 'put':
            // Set up out PUT variables
            parse_str(file_get_contents('php://input'), $this->_put_args);
        break;

        case 'delete':
            // Set up out PUT variables
            parse_str(file_get_contents('php://input'), $this->_delete_args);
        break;

Są tu dwie opcje, podchodzę do tego w niewłaściwy sposób lub gdzieś w moich bibliotekach jest błąd. Gdybyś mógł dać mi znać, czy to powinno teoretycznie zadziałać, mogę po prostu wkurzyć debugowanie, dopóki go nie rozwiążę.

Nie chcę tracić więcej czasu na podejście, które jest zasadniczo błędne.

Phil Sturgeon
źródło
PUT działa dobrze, po prostu USUŃ parametry, aby teraz martwić się o ustawienie.
Phil Sturgeon
1
To pytanie jest mylące. Czy chodzi o wysyłanie POST / DELETEparametry, czy odbiór POST / DELETEparametry?
jameshfisher

Odpowiedzi:

68

Zamiast używać CURLOPT_PUT = TRUEuse, CURLOPT_CUSTOMREQUEST = 'PUT' a CURLOPT_CUSTOMREQUEST = 'DELETE'następnie po prostu ustaw wartości za pomocą CURLOPT_POSTFIELDS.

Phil Sturgeon
źródło
Jak mogę otrzymać POSTFIELDS po stronie API / serwera?
Daniel,
48

Oto kod, który może być pomocny dla innych, którzy chcą obsługiwać parametry PUT i DELETE. Możesz ustawić $_PUTi $_DELETEza pośrednictwem $GLOBALS[], ale nie będą one bezpośrednio dostępne w funkcjach, chyba że zostaną zadeklarowane globallub dostępne za pośrednictwem $GLOBALS[]. Aby obejść ten problem, stworzyłem prostą klasę do odczytywania argumentów żądań GET / POST / PUT / DELETE. To również zapełnia $_REQUESTsię parametrami PUT / DELETE.

Ta klasa przeanalizuje parametry PUT / DELETE i będzie również obsługiwać GET / POST.

class Params {
  private $params = Array();

  public function __construct() {
    $this->_parseParams();
  }

  /**
    * @brief Lookup request params
    * @param string $name Name of the argument to lookup
    * @param mixed $default Default value to return if argument is missing
    * @returns The value from the GET/POST/PUT/DELETE value, or $default if not set
    */
  public function get($name, $default = null) {
    if (isset($this->params[$name])) {
      return $this->params[$name];
    } else {
      return $default;
    }
  }

  private function _parseParams() {
    $method = $_SERVER['REQUEST_METHOD'];
    if ($method == "PUT" || $method == "DELETE") {
        parse_str(file_get_contents('php://input'), $this->params);
        $GLOBALS["_{$method}"] = $this->params;
        // Add these request vars into _REQUEST, mimicing default behavior, PUT/DELETE will override existing COOKIE/GET vars
        $_REQUEST = $this->params + $_REQUEST;
    } else if ($method == "GET") {
        $this->params = $_GET;
    } else if ($method == "POST") {
        $this->params = $_POST;
    }
  }
}
Bryan Drewery
źródło
16

Pamiętaj tylko, że większość serwerów WWW nie obsługuje żądań PUT & DELETE. Ponieważ tworzysz bibliotekę, radzę pomyśleć o uwzględnieniu tego. Zwykle istnieją dwie konwencje, których można użyć do naśladowania operacji PUT & DELETE za pomocą POST.

  1. użyj niestandardowej zmiennej POST (np. _METHOD = PUT), która zastępuje POST
  2. ustaw niestandardowy nagłówek HTTP (np. X-HTTP-Method-Override: PUT)

Ogólnie rzecz biorąc, większość usług RESTful, które nie pozwalają bezpośrednio na PUT & DELETE, będzie obsługiwać co najmniej jedną z tych strategii. Możesz użyć cURL, aby ustawić niestandardowy nagłówek, jeśli potrzebujesz, za pomocą CURLOPT_HTTPHEADERopcji.

// ex...
curl_setopt($ch, CURLOPT_HTTPHEADER, array('X-HTTP-Method-Override: PUT') );
piekarnik
źródło
3

Myślę, że mieszasz czasowniki - PUT służy do umieszczania pliku, POST służy do wysyłania zmiennych (chociaż możesz POST plik).

Aby ustawić zmienne post, użyj CURLOPT_POSTFIELDSz ciągiem param1=val1&param2=val2lub tablicą asocjacyjną.

Aby wykonać DELETE, będziesz chciał użyć opcji curl CURLOPT_CUSTOMREQUEST

Adam Hopkinson
źródło
1
PUT i DELETE obsługują wysyłanie dodatkowych argumentów. Możesz to zrobić za pomocą wiersza poleceń podczas pracy z curl, ale nie mogę ustalić, jak wysłać za pomocą PHP-cURL. Na przykład, ponieważ jest to przeznaczone dla REST, potrzebuję sposobu, aby zaznaczyć, co usuwam. Jeśli usuwam identyfikator użytkownika, chcę mieć możliwość przekazywania identyfikatora bez zaśmiecania adresu URL. Interfejsy API, takie jak Twitter, obsługują tylko GET / POST, więc możesz umieścić to w adresie URL, ale inne API REST mogą nie obsługiwać tego rodzaju rzeczy, więc muszę wysłać dla niego parametr usuwania.
Phil Sturgeon
1
Ok, mam parametry PUT działające, zamieniłem CURLOPT_PUT = TRUE na CURLOPT_CUSTOMREQUEST = 'PUT' i to działa dobrze. Jak, do diabła, mam ustawić DELETE?
Phil Sturgeon
CURLOPT_CUSTOMREQUEST = 'DELETE', a następnie może użyć ciągu zapytania dla parametrów
Adam Hopkinson
1
Zamknij, starałem się unikać ich używania w ciągu zapytania, jak już wspomniałem. Okazuje się, że możesz używać CURLOPT_POSTFIELDS z PUT i DELETE, gdy używasz CURLOPT_CUSTOMREQUEST = 'DELETE. Dziękuję za twoją opinię, ale w końcu rozwiązałem to sam :-)
Phil Sturgeon
2
Czy ty? W ogóle nie pomogłem?
Adam Hopkinson
2

To jest moja wersja DELETE for CI. Przyjmuje argumenty w stylu GET dla DELETE, nawet te same argumenty nazw, np .: GET / some / url? Id = 1 & id = 2 & id = 3

protected function _parse_delete()
{
    $query = $_SERVER['QUERY_STRING'];
    if ( !empty( $query ) )
    {
        foreach( explode('&', $query ) as $param )
        {
            list($k, $v) = explode('=', $param);
            $k = urldecode($k);
            $v = urldecode($v);
            if ( isset( $this->_delete_args[$k] ) )
            {
                if ( is_scalar( $this->_delete_args[$k] ) )
                {
                    $this->_delete_args[$k] = array( $this->_delete_args[$k] );
                }
                $this->_delete_args[$k][] = $v ;
            }
            else
            {
                $this->_delete_args[$k] = $v;
            }
        }
    }
}
Patrick Savalle
źródło
1

Oto jak rozwiązać problem z DELETE:

== >> w REST_Controller.php zastępuję funkcję delault _parse_delete () przez:

protected function _parse_delete()
{
    $this->_delete_args = $_DELETE;
    $this->request->format and $this->request->body = file_get_contents('php://input');
    // Set up out DELETE variables (which shouldn't really exist, but sssh!)
    parse_str(file_get_contents('php://input'), $this->_delete_args);
}

;) mi to pasuje!

okobsamoht
źródło
1
$ _DELETE ;? Po prostu otrzymuję zmienną niezdefiniowaną błąd: _DELETE
Valor_