在 PHP 中处理 PUT/DELETE 参数

我正在我的 用于 CodeIgniter 的 REST 客户端库和我正在努力解决如何在 PHP 中发送 PUT 和 DELETE 参数。

在一些地方,我看到人们使用这些选项:

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

烦人的是,这似乎没有任何作用。这是设置 PUT 参数的正确方法吗?

如果是,如何设置 DELETE 参数?

$this-> option ()是我的库的一部分,它只是构建 CURLOPT _ XX 常量数组,并在执行构建的 cURL 请求时将它们发送到 cURL _ setopt _ array ()。

我尝试使用以下代码读取 PUT 和 DELETE 参数:

        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;

这里有两个选择,我正在以错误的方式处理这个问题,或者在我的库中的某个地方有一个 bug。如果你能让我知道,如果这在理论上应该工作,我可以只是锤子在调试,直到我解决它。

我不想在一个根本错误的方法上浪费更多的时间。

75373 次浏览

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

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

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.

  1. use a custom POST variable (ex. _METHOD=PUT) which overrides POST
  2. 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') );

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

This is how i sole my DELETE problem:

==>> in REST_Controller.php i replace the delault _parse_delete() function by :

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

;) it works for me!

This is my version of the DELETE for CI. It accepts GET-style arguments for the DELETE, even same name arguments, i.e.: 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;
}
}
}
}