Manejo de argumentos PUT / DELETE en PHP

84

Estoy trabajando en mi biblioteca de cliente REST para CodeIgniter y estoy luchando para averiguar cómo enviar argumentos PUT y DELETE en PHP.

En algunos lugares he visto personas que usan las opciones:

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

Es molesto que esto parezca no hacer nada. ¿Es esta la forma correcta de configurar los parámetros PUT?

Si es así, ¿cómo configuro los parámetros DELETE?

$ this-> option () es parte de mi biblioteca, simplemente crea una matriz de constantes CURLOPT_XX y las envía a curl_setopt_array () cuando se ejecuta la solicitud cURL construida.

Estoy intentando leer los parámetros PUT y DELETE usando el siguiente código:

        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;

Hay dos opciones aquí, me estoy acercando a esto de la manera incorrecta o hay un error en alguna parte de mis bibliotecas. Si pudiera hacerme saber si esto debería funcionar teóricamente, puedo trabajar en la depuración hasta que lo resuelva.

No quiero perder más tiempo en un enfoque que es fundamentalmente incorrecto.

Phil Sturgeon
fuente
PUT funciona bien, solo BORRAR los parámetros para preocuparse por la configuración ahora.
Phil Sturgeon
1
Esta pregunta es confusa. ¿Se trata de enviar POST / DELETEparámetros o recibir POST / DELETEparámetros?
jameshfisher

Respuestas:

68

En lugar de usar CURLOPT_PUT = TRUEuse CURLOPT_CUSTOMREQUEST = 'PUT' y CURLOPT_CUSTOMREQUEST = 'DELETE'luego simplemente establezca valores con CURLOPT_POSTFIELDS.

Phil Sturgeon
fuente
¿Cómo recibo POSTFIELDS en el lado api / servidor?
Daniel
48

Aquí hay un código que puede ser útil para otros que quieran manejar los parámetros PUT y DELETE. Puede configurar $_PUTy $_DELETEvia $GLOBALS[], pero no serán directamente accesibles en funciones a menos que se declare globalo acceda a través de $GLOBALS[]. Para solucionar esto, he creado una clase simple para leer argumentos de solicitud GET / POST / PUT / DELETE. Esto también se completa $_REQUESTcon los parámetros PUT / DELETE.

Esta clase analizará los parámetros PUT / DELETE y también admitirá 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
fuente
16

Solo recuerde, la mayoría de los servidores web no manejan solicitudes PUT & DELETE. Dado que está creando una biblioteca, le sugiero que piense en la contabilidad de esto. Por lo general, hay dos convenciones que puede utilizar para imitar PUT & DELETE mediante POST.

  1. use una variable POST personalizada (por ejemplo, _METHOD = PUT) que anula POST
  2. establecer un encabezado HTTP personalizado (por ejemplo, X-HTTP-Method-Override: PUT)

En términos generales, la mayoría de los servicios RESTful que no permiten PUT & DELETE directamente apoyarán al menos una de esas estrategias. Puede usar cURL para establecer un encabezado personalizado si lo necesita a través de la CURLOPT_HTTPHEADERopción.

// ex...
curl_setopt($ch, CURLOPT_HTTPHEADER, array('X-HTTP-Method-Override: PUT') );
Owen
fuente
3

Creo que está mezclando sus verbos: PUT es para colocar un archivo, POST es para publicar variables (aunque puede POST un archivo).

Para configurar las variables de publicación, utilice CURLOPT_POSTFIELDScon una cadena de param1=val1&param2=val2o una matriz asociativa.

Para hacer un DELETE, querrás usar la opción curl CURLOPT_CUSTOMREQUEST

Adam Hopkinson
fuente
1
PUT y DELETE admiten el envío de argumentos adicionales. Puede hacer esto a través de la línea de comando cuando trabaja con curl, pero no puedo averiguar cómo enviar con PHP-cURL. Por ejemplo, como esto es para REST, necesito una forma de marcar lo que estoy eliminando. Si estoy eliminando la identificación de usuario, quiero poder pasar la identificación sin saturar la URL. Las API como Twitter solo admiten GET / POST, por lo que puede poner eso en la URL, pero es posible que otras API REST no admitan este tipo de cosas, por lo que necesito enviar un parámetro de eliminación para ello.
Phil Sturgeon
1
Ok, tengo los parámetros PUT funcionando, cambié CURLOPT_PUT = TRUE por CURLOPT_CUSTOMREQUEST = 'PUT' y eso funciona bien. Ahora, ¿cómo diablos configuro DELETE?
Phil Sturgeon
CURLOPT_CUSTOMREQUEST = 'DELETE', luego use la cadena de consulta para los parámetros tal vez
Adam Hopkinson
1
Cerca, estaba tratando de evitar usarlos en la cadena de consulta como ya mencioné. Resulta que puede usar CURLOPT_POSTFIELDS con PUT y DELETE cuando usa CURLOPT_CUSTOMREQUEST = 'DELETE. Gracias por sus comentarios, pero al final lo resolví yo mismo :-)
Phil Sturgeon
2
¿Tuviste? ¿Entonces no ayudé en absoluto?
Adam Hopkinson
2

Esta es mi versión del DELETE para CI. Acepta argumentos de estilo GET para DELETE, incluso argumentos del mismo nombre, es decir: 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
fuente
1

Así es como soluciono mi problema DELETE:

== >> en REST_Controller.php reemplazo la función delault _parse_delete () por:

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);
}

;) ¡esto funciona para mi!

okobsamoht
fuente
1
$ _DELETE ;? Acabo de obtener una variable indefinida de error: _DELETE
Valor_