문제

나는 동적 SQL의 유연성을 좋아하고 준비된 진술의 보안 + 개선 성능을 좋아합니다. 따라서 내가 정말로 원하는 것은 동적 준비 된 진술입니다. Bind_param과 Bind_result는 "고정 된"인수를 수락하기 때문에 문제가됩니다. 그래서 나는이 문제를 해결하기 위해 eval () 문을 사용했습니다. 그러나 나는 이것이 나쁜 생각이라고 느낀다. 다음은 내가 의미하는 바에 대한 예제 코드입니다

// array of WHERE conditions
$param = array('customer_id'=>1, 'qty'=>'2');
$stmt = $mysqli->stmt_init();

$types = ''; $bindParam = array(); $where = ''; $count = 0;

// build the dynamic sql and param bind conditions
foreach($param as $key=>$val)
{
    $types .= 'i';
    $bindParam[] = '$p'.$count.'=$param["'.$key.'"]'; 
    $where .= "$key = ? AND ";
    $count++;
}

// prepare the query -- SELECT * FROM t1 WHERE customer_id = ? AND qty = ?
$sql = "SELECT * FROM t1 WHERE ".substr($where, 0, strlen($where)-4);
$stmt->prepare($sql);

// assemble the bind_param command
$command = '$stmt->bind_param($types, '.implode(', ', $bindParam).');';

// evaluate the command -- $stmt->bind_param($types,$p0=$param["customer_id"],$p1=$param["qty"]);
eval($command);

마지막 at at at at at at at at are are are nade? 변수 이름 $ param 뒤에 값을 캡슐화하여 코드 주입을 피하려고 노력했습니다.

누구든지 의견이나 다른 제안이 있습니까? 알아야 할 문제가 있습니까?

도움이 되었습니까?

해결책

사용하는 것이 위험하다고 생각합니다 eval() 여기.

이 시도:

  • 물음표로 SQL 문자열을 빌드하기 위해 매개 변수 배열을 반반하십시오. "SELECT * FROM t1 WHERE p1 = ? AND p2 = ?"
  • 전화 prepare() 그것에
  • 사용 call_user_func_array() 전화를 걸기 위해 bind_param(), 동적 매개 변수 배열을 전달합니다.

코드:

call_user_func_array(array($stmt, 'bind_param'), array($types)+$param);

다른 팁

나는 $ _get과 같은 배열을 배열로 암송하는 필터 기능을 만들었습니다.

모델 클래스에서 스키마를 포함한 몇 가지 속성을 정의했습니다.

private $table_name = "products";

protected $schema = [
    'id' => 'INT',
    'name' => 'STR',
    'description' => 'STR',
    'size' => 'STR',
    'cost' => 'INT',
    'active' => 'BOOL'
];

그런 다음 조건의 비 사회적 배열을 암송하는 필터 방법 :

function filter($conditions)
{
    $vars   = array_keys($conditions);
    $values = array_values($conditions);

    $where = '';
    foreach($vars as $ix => $var){
        $where .= "$var = :$var AND ";
    }
    $where =trim(substr($where, 0, strrpos( $where, 'AND ')));

    $q  = "SELECT * FROM {$this->table_name} WHERE $where";
    $st = $this->conn->prepare($q);

    foreach($values as $ix => $val){
        $st->bindValue(":{$vars[$ix]}", $val, constant("PDO::PARAM_{$this->schema[$vars[$ix]]}"));
    }

    $st->execute();
    return $st->fetchAll(PDO::FETCH_ASSOC);
}

결과를 필터링하는 데 큰 도움이됩니다

항상 mysql_real_escape_string ()을 사용할 수 있기 때문에 준비된 진술과 바운드 인수가 필요하지 않습니다. 그리고 당신이 옳습니다. 동적으로 생성 된 SQL은 훨씬 유연하고 가치가 있습니다.

다음은 일반 MySQL_* 인터페이스를 사용하는 간단한 예입니다.

// Array of WHERE conditions
$conds = array("customer_id" => 1, "qty" => 2);

$wherec = array("1");
foreach ($conds as $col=>$val) $wherec[] = sprintf("`%s` = '%s'", $col, mysql_real_escape_string($val));

$result_set = mysql_query("SELECT * FROM t1 WHERE " . implode(" AND ", $wherec);

물론, 이것은 단순한 예이며, 유용하게 만들기 위해서는 그것을 많이 구축하고 개선해야하지만 아이디어를 보여주고 매우 유용합니다. 예를 들어, 여기에는 새로운 행을 임의의 테이블에 삽입하는 완전히 일반적인 기능이 있습니다.

function insert($table, $record) {
    $cols = array();
    $vals = array();
    foreach (array_keys($record) as $col) $cols[] = sprintf("`%s`", $col);
    foreach (array_values($record) as $val) $vals[] = sprintf("'%s'", mysql_real_escape_string($val));

    mysql_query(sprintf("INSERT INTO `%s`(%s) VALUES(%s)", $table, implode(", ", $cols), implode(", ", $vals)));
}

// Use as follows:
insert("customer", array("customer_id" => 15, "qty" => 86));
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top