Friday, May 4, 2012

Handling PUT/DELETE arguments in PHP


I am working on my REST client library for CodeIgniter and I am struggling to work out how to send PUT and DELETE arguments in PHP.



In a few places I have seen people using the options:




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



Annoyingly, this seems to do nothing. Is this the correct way to set PUT parameters?



If so, how do I set DELETE parameters?



*$this->option() is part of my library, it simply builds up an array of CURLOPT_XX constants and sends them to curl_setopt_array() when the built up cURL request is executed.*



I am attempting to read PUT and DELETE parameters using the following code:




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;



There are two options here, I am approaching this in the wrong way or there is a bug somewhere in my libraries. If you could let me know if this should theoretically work I can just hammer away on debug until I solve it.



I dont want to waste any more time on an approach that is fundamentally wrong.


Source: Tips4all

4 comments:

  1. Instead of using CURLOPT_PUT = TRUE use CURLOPT_CUSTOMREQUEST = 'PUT'
    and CURLOPT_CUSTOMREQUEST = 'DELETE' then just set values with CURLOPT_POSTFIELDS.

    Works perfectly!

    ReplyDelete
  2. Just remember, most webservers do not handle PUT & DELETE requests. Since you're making a library, I'd suggest thinking about accounting for this. Typically, there are two conventions you can use to mimic PUT & DELETE via POST.


    use a custom POST variable (ex. _METHOD=PUT) which overrides POST
    set a custom HTTP header (ex. X-HTTP-Method-Override: PUT)


    Generally speaking, most RESTful services that don't allow PUT & DELETE directly will support at least one of those strategies. You can use cURL to set a custom header if you need via the CURLOPT_HTTPHEADER option.

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

    ReplyDelete
  3. Here is some code which may be helpful for others wanting to handle PUT and DELETE params. You are able to set $_PUT and $_DELETE via $GLOBALS[], but they will not be directly accessible in functions unless declared global or accessed via $GLOBALS[]. To get around this, I've made a simple class for reading GET/POST/PUT/DELETE request arguments. This also populates $_REQUEST with PUT/DELETE params.

    This class will parse the PUT/DELETE params and support GET/POST as well.

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

    ReplyDelete
  4. I think you're mixing your verbs - PUT is for putting a file, POST is for posting variables (although you can POST a file).

    To set the post variables, use CURLOPT_POSTFIELDS with either a string of param1=val1&param2=val2 or an associative array.

    To do a DELETE, you'll want to use the curl option CURLOPT_CUSTOMREQUEST

    ReplyDelete