为PUT或DELETE请求覆盖$ _POST

时间:2011-06-07 18:39:51

标签: php rest

在PHP中,我希望能够全局访问PUTDELETE个vars,类似于全局访问GETPOST vars的方式。我最初考虑将数据分别添加到全局命名空间中的$_PUT$_DELETE,但后来我意识到每个请求的数据都存储在消息体中,所以没有办法超过来自POSTPUTDELETE请求的一个数据集。

是否有覆盖$_POST变量的副作用?

即。 str_parse( file_get_contents( 'php://input' ), $_POST );

我是愚蠢的,还是有更好的方式来访问PUTDELETE数据?


编辑以澄清我的想法:

我非常清楚$_POST中数据的来源,事实上我在前面的问题中提到过它。如果向服务器发送HTTP POST请求,则数据将存储在php://input中。如果向服务器发送HTTP PUT或DELETE请求,则数据将存储在完全相同的位置,这意味着$_POST将为空(尽管数据可用,因此没有数据POSTed

另一方面,GET请求通过查询字符串传递。这允许同时传递$_POST$_GET变量。同时传递POSTPUT or DELETE变量

如果我在$_POSTphp://input请求上覆盖PUT DELETE,则不会丢失数据。

添加的替代选择:

global $_PUT;
global $_DELETE;

到函数的开头似乎很愚蠢,因为我一次只能使用一个

我的第一个问题,即我真正想要回答的问题,是关于覆盖$_POST存在哪些副作用或问题。我不可能成为第一个尝试傻事的人:

$_POST['foo'] = 'bar';

我只是担心如果我做了类似的事情,它可能不会在范围内保留。

4 个答案:

答案 0 :(得分:15)

你会在整个互联网上看到这个被称为“坏习惯”的东西,但如果你真的进入为什么这是“坏习惯”,那么答案就会变得模糊。最具体的原因是“公共汽车撞击”的场景经常被大肆渲染 - 如果项目交给新的开发人员怎么办?

撇开手(毕竟你可以发表评论),确实没有令人信服的理由这样做,但同样,没有令人信服的理由 也做到了。如果您想要全局,为什么不将值放在$_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;
    }
}

答案 1 :(得分:4)

离开Post并获取原样。它不应该被修改,因为它只是为了阅读目的。创建$ _PUT和$ _DELETE globals:

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

未经测试,但您应该明白这一点。几个星期前我一直在寻找一个休息框架,并决定使用python。休息(http://www.recessframework.org/)听起来很有希望

答案 2 :(得分:3)

您不应直接修改$_POST,因为它代表来自客户端的值。将其视为只读,并对用户定义的变量进行任何修改。

作为访问PUT和DELETE数据的后续工作,目前PHP内置的超级全局没有直接访问这些数据。由于数据是文件数据,这可能相当大,因此在典型的赋值语句$variable = $_PUT['file'];中读取整个文件内容的有用性和效率值得怀疑。相反,它应该以块的形式阅读。因此,使用情况与从任何其他文件输入资源读取一致。

更多关于PUT的信息:

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

答案 3 :(得分:-1)

如果您创建“请求”对象,那么无论请求是通过HTTP,命令行还是通过HTML5 Web套接字,您都可以使用统一的方式来访问请求数据。然后,您可以在全局范围内访问请求对象,或将其作为参数传递给所需的函数或方法。

理想情况下,您可以在静态或全局变量中存储独立于请求的数据,例如:无论请求如何都是“静态”的设置,以及可由业务逻辑使用的本地变量或对象中特定于请求的数据。例如,如果您有一个Web套接字服务器,那么在单个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)非常简单。