Могу ли я связать параметр с оператором PDO в качестве оператора сравнения? - PullRequest
0 голосов
/ 05 декабря 2011

это код

class opinion
{
   private $dbh;
   var $opinionid,$opinion,$note,$actorid,$dateposted;
   var $isnew=FALSE;
   function loadby($column,$value,$operator="="){
       $dbh = new PDO(I deleted parameters here);
       $statement=$dbh->prepare("select * from fe_opinion where :column :operator :value");
       $statement->bindParam(":column", $column);
       $statement->bindParam(":value", $value);
       $statement->bindParam(":operator", $operator); //UNSURE, DOUBTFUL
       $statement->bindColumn("opinionid", $this->opinionid);
       $statement->bindColumn("opinion", $this->opinion);
       $statement->bindColumn("note", $this->note);
       $statement->bindColumn("actorid", $this->actorid);
       $statement->bindColumn("dateposted", $this->dateposted);
       $statement->fetch();
       return $statement->rowCount(); //please be 1
   }
}

инъекция безопасна?

       $statement->bindParam(":operator", $operator); //UNSURE, DOUBTFUL

Можно ли связать параметр с оператором PDO в качестве оператора сравнения?

Ответы [ 4 ]

2 голосов
/ 05 декабря 2011

Нет, вы не можете связывать такие операторы.В качестве обходного пути вы можете динамически создать «базовый» SQL-запрос и использовать белый список операторов (что вполне уместно), чтобы оставаться в безопасности от внедрения:

function loadby($column,$value,$operator="="){ 
   $dbh = new PDO(...); 
   $operator = getOperator($operator);
   if(!$operator) {
       // error handling
   }
   $statement=$dbh->prepare("select * from fe_opinion where :column $operator :value");
   // the rest like you already do it
} 

function getOperator($operator) {
   $allowed_ops = array('=', '<', '>'); // etc
   return in_array($operator, $allowed_ops) ? $operator : false;
}

Кроме этого, все остальное в порядке и внедрение"по определению".

0 голосов
/ 05 декабря 2011

Вы действительно можете сделать это.SQL просто становится все сложнее.В зависимости от количества комбинаций, sql может быть действительно огромным.Но иногда, когда есть только несколько вариантов, это хорошо.

select * 
  from someTable

where (case :column
       when 'age' then (case :operator
                               when '>' then age > :value
                               when '<' then age < :value
                        end)
       when 'price' then (case :operator
                               when '>' then price > :value
                               when '<' then price < :value
                        end)
      end)

  and someOtherCol = 'foo'

Значение: может быть и другим столбцом, но вам нужно будет снова вставить еще одну конструкцию case, как для первого столбца, икомбинации действительно взлетают.

Во всяком случае ... просто хотел показать, что это может быть сделано.

0 голосов
/ 05 декабря 2011

В зависимости от СУБД и драйвера PHP подготовленные операторы могут быть «реальными» или эмулированными.

В первом случае параметры связывания обрабатываются непосредственно СУБД.В таком случае обработка оператора в качестве параметра, вероятно, вызовет синтаксическую ошибку.Анализатор SQL будет анализировать запрос, даже не просматривая параметры, и не найдет допустимый код SQL для работы.

Во втором случае параметры связывания эмулируются драйвером: входные значения вставляются в код SQL (с адекватным выходом) и СУБД получает полный регулярный запрос.Я не совсем уверен в том, как будут вести себя текущие драйверы (мне нужно было бы это проверить), но даже если они не будут жаловаться на недопустимый SQL, они рано или поздно попадут в стену: операторы SQL не являются строками.

Теперь, было бы неплохо реализовать это когда-нибудь?Я сомневаюсь, что это:

  • Вы не выиграете от предварительно проанализированного SQL при выполнении повторяющихся запросов: если вы измените операторы, вы измените запрос.
  • Вы не получите безопасный код SQL.Как ты мог?
0 голосов
/ 05 декабря 2011

Как уже упоминалось в комментарии, я не думаю, что можно избежать оператора и заставить его работать так, как вы ожидаете. Результирующий запрос, вероятно, будет выглядеть примерно так:

'column' '=' 'value';

Вам не нужно выходить из оператора, чтобы избежать инъекционных атак, вы можете проверить свой оператор перед добавлением его в строку, рассмотрите:

class opinion
{
    $validOperators = array('=', '>=', '>', '=<', '<');

    function loadby($column,$value,$operator="=") {

        // Validate operator
        if (!in_array($operator, self::$validOperators)) {
            throw new Exception('Invalid $operator ' . $operator . ')';
        }

        $statement=$dbh->prepare("select * from fe_opinion where :column " . $operator . " :value");
    }
}
...