尝试并同时捕获执行

时间:2017-12-04 11:12:18

标签: php

所以我有这个OOP登录&注册系统,使用户能够更改他/她的名字。

当用户按下“更新”按钮时,他/她的名字在DB中被更改,问题是它改变了DB中的名称,而不是重定向用户我希望他/她被重定向的地方我得到了错误只有在无法更改该名称时才会出现。

user.php的

<?php

class User{
private $_db,
        $_data,
        $_sessionName,
        $_cookieName,
        $_isLoggedIn;

public function __construct($user = null){
    $this->_db = DB::getInstance();

    $this->_sessionName = Config::get('session/session_name');
    $this->_cookieName = Config::get('remember/cookie_name');

    if(!$user){
        if(Session::exists($this->_sessionName)){
            $user = Session::get($this->_sessionName);

            if($this->find($user)){
                $this->_isLoggedIn = true;
            } else{
                //process logout
            }
        }
    } else{
        $this->find($user);
    }
}

public function update($fields = array(), $id = null){

    if(!$id && $this->isLoggedIn()){
        $id = $this->data()->id;
    }

    if(!$this->_db->update('users', $id, $fields)){
        throw new Exception('There was a problem updating your profile.');
    }
}

public function create($fields = array()){
    if(!$this->_db->insert('users', $fields)){
        throw new Exception('There was a problem creating an account');
    }
}

public function find($user = null){
    if($user){
        $field = (is_numeric($user)) ? 'id' : 'username';
        $data = $this->_db->get('users', array($field, '=', $user));

        if($data->count()){
            $this->_data = $data->first();
            return true;
        }
    }
    return false;
}

public function login($username = null, $password = null, $remember = false){
    if(!$username && !$password && $this->exists()){
        Session::put($this->_sessionName, $this->data()->id);
    } else{
        $user = $this->find($username);
        if($user){
            if($this->data()->password === Hash::make($password, $this->data()->salt)){
                Session::put($this->_sessionName, $this->data()->id);

                if($remember){
                    $hash = Hash::unique();
                    $hashCheck = $this->_db->get('users_session', array('user_id', '=', $this->data()->id));

                    if(!$hashCheck->count()){
                        $this->_db->insert('users_session',array(
                            'user_id' => $this->data()->id,
                            'hash' => $hash
                        ));
                    } else{
                        $hash = $hashCheck->first()->hash;
                    }
                    Cookie::put($this->_cookieName, $hash, Config::get('remember/cookie_expiry'));
                }

                return true;
            }
        }
    }
    return false;
}

public function exists(){
    return(!empty($this->_data)) ? true : false;
}

public function logout(){
    $this->_db->delete('users_session', array('user_id', '=', $this->data()->id));

    Session::delete($this->_sessionName);
    Cookie::delete(Config::get('remember/cookie_name'));
}

public function data(){
    return $this->_data;
}

public function isLoggedIn(){
    return $this->_isLoggedIn;
}
}

edit-profile.php

<?php

    $user = new User();
    if(!$user->isLoggedIn()){
        Redirect::to('login');
    }

    if(Input::exists()){
        if(Token::check(Input::get('token'))){

            $validate = new Validate();
            $validation = $validate->check($_POST, array(
                'name' => array(
                    'required' => true,
                    'min' => 2,
                    'max' => 50
                )
            ));

            if($validation->passed()){

                try{
                    $user->update(array(
                        'name' => Input::get('name')
                    ));

                    Session::flash('flash', 'Your profile has been edited with success!');
                    Redirect::to('flash');

                } catch(Exception $e){
                    die($e->getMessage());
                }
            } else{
                foreach($validation->errors() as $error){
                    echo $error . '<br />';
                }
            }

        }
    }

    ?>

    <form action="" method="post">
        <div class="field">
            <input type="text" name="name" value="<?php echo escape($user->data()->name); ?>">
        </div>
        <input type="submit" value="Update">
        <input type="hidden" name="token" value="<?php echo Token::generate(); ?>">
    </form>

我不知道为什么会发生这种情况

这是我的DB.class中的update()方法

public function update($table, $id, $fields){
        $set = '';
        $x = 1;

        foreach ($fields as $name => $value) {
            $set .= "{$name} = ?";
            if($x < count($fields)){
                $set .= ', ';
            }
            $x++;
        }

        $sql = "UPDATE {$table} SET {$set} WHERE id = {$id}";

        if($this->query($sql, $fields)->error()){
            return true;
        }
        return false;
    }

1 个答案:

答案 0 :(得分:0)

用于更新功能

public function update($table, $id, $fields){
    $set = '';
    $x = 1;
    foreach ($fields as $name => $value) {
        $set .= "{$name} = ?";
        if($x < count($fields)){
            $set .= ', ';
        }
        $x++;
    }
    $sql = "UPDATE {$table} SET {$set} WHERE id = {$id}";
    if($this->query($sql, $fields)->error()){
        return true;
    }
    return false;
}

取而代之的是

public function update($table, $id, $fields){

    $set = [];

    foreach ($fields as $name => $value) {
       $set[] = "{$name} = ?";
    }

    $set = implode(', ', $set);

    $sql = "UPDATE {$table} SET {$set} WHERE id = ?";
    $fields[] = $id; //id should always be the last ?
    if($this->query($sql, $fields)->error()){
        return true;
    }
    return false;
}

此外,tableid甚至$fields的键都可能被用作SQL注入的向量。您可能会在使用它们的地方输入它。但这是可能的,因为您没有根据白名单检查表,并且无论何时将值连接到SQL,都有可能被利用。所需要的只是一个错误,你上课时不应该允许其他地方的编码错误来破坏它的安全性。

您可以从数据库本身获取表格列表。

$statement = 'SELECT `TABLE_NAME` FROM `information_schema`.`TABLES` WHERE `TABLE_SCHEMA` LIKE "'.$database.'"';

因此,当您连接到数据库时,您可以设置可接受表的列表,然后检查何时放入表(使用in_array等)。只是一个想法。

也可以包含$fields数组的键,因为您可以执行类似于表的操作。但是有了这个查询

SHOW COLUMNS FROM {table}

例如,假设一个帖子请求的输入与您的数组$fields匹配。所有人都必须做的是向服务器发送一个请求,其中包含密钥中的SQL Attack部分而不是值,并且您不受保护。这样的事情(不要在没有备份的情况下放弃你的数据库,我觉得我应该这样说。)

  $_POST['1=1; DROP DATABASE --'] = true; 

构建查询时,您将拥有

INSERT INTO table SET 1=1; DROP DATABASE -- = ?, {field} = ? .. rest of query

--在SQL中启动注释,因此在--之后没有任何内容可以防止发生错误。所以要小心只是将post键转储到SQL中。我不确定1=1是否可行,但他们可以轻松地使用输入列表中的字段。这只是为了举例。

给我这一行

   if($this->query($sql, $fields)->error()){
        return true;
   }else{
        return false;
   }

如果错误返回true,请确定是否是这种情况,因为我不知道$this->query->error()是什么,但我想{{1}必须返回$this->query或一些包含错误的对象。它只是令人困惑的措辞。