2013-01-19 42 views
6

Tôi biết điều này đã được yêu cầu 1000 lần, nhưng đối với một số lý do tôi tiếp tục đập đầu mình vào tường agains ..PDO PHP bindValue không hoạt động

này hoạt động:

$sql = 'SELECT a.eventCode, a.eventTime, a.teamCode, a.playerCode, b.lastName, b.firstName, b.number, a.xCoord, a.yCoord, a.id '; 
$sql = $sql . 'FROM events a, players b '; 
$sql = $sql . 'WHERE a.regGUID in (' . $regGUID . ') and '; 
$sql = $sql . 'a.playerCode=b.playerCode and a.gameCode = "' . $game . '" order by a.eventTime desc, a.actionCode asc'; 
$stmt = $db->prepare($sql); 
$results = $stmt->execute(); 

doesn này 't:

$sql = 'SELECT a.eventCode, a.eventTime, a.teamCode, a.playerCode, b.lastName, b.firstName, b.number, a.xCoord, a.yCoord, a.id '; 
$sql = $sql . 'FROM events a, players b '; 
$sql = $sql . 'WHERE a.regGUID in (:regGUID) and '; 
$sql = $sql . 'a.playerCode=b.playerCode and a.gameCode = :game order by a.eventTime desc, a.actionCode asc'; 
$stmt = $db->prepare($sql); 
$stmt->bindValue(':regGUID', $regGUID, PDO::PARAM_STR); 
$stmt->bindValue(':game', $game, PDO::PARAM_STR); 
$results = $stmt->execute(); 

Tôi đang thiếu gì? Cảm ơn

+0

là regGUID thực sự là một chuỗi? – hek2mgl

+1

Đảm bảo rằng bạn có thể * xem * lỗi PDO bằng cách thay đổi từ chế độ lỗi im lặng mặc định: '$ db-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_WARNING)' – eggyal

+4

Đặt PDO thành [ném ngoại lệ về lỗi] (http : //us.php.net/manual/en/pdo.error-handling.php), xem nó có ném gì không. Có phải '$ regGUID' là một GUID đơn hay danh sách GUID được phân cách bằng dấu phẩy không? Nếu sau này, mỗi GUID phải được ràng buộc như một biến riêng biệt. – DCoder

Trả lời

5

Vấn đề là ở đây:

$sql = $sql . 'WHERE a.regGUID in (:regGUID) and '; 
$stmt->bindValue(':regGUID', $regGUID, PDO::PARAM_STR); 

Tôi giả định $ regGUID là danh sách các chuỗi được trích dẫn bằng dấu phẩy.

Mỗi thông số truy vấn chỉ chấp nhận một giá trị vô hướng duy nhất.Không phải danh sách giá trị.

Vì vậy, bạn có hai lựa chọn:

  1. Tiếp tục suy chuỗi $ regGUID, ngay cả khi bạn sử dụng các thông số cho các giá trị vô hướng khác. Nhưng bạn vẫn muốn cẩn thận để tránh SQL injection, vì vậy bạn phải tạo chuỗi $ regGUID một cách chính xác. Bạn không thể chỉ gọi PDO :: quote() trên toàn bộ chuỗi, mà sẽ làm cho nó một chuỗi trích dẫn duy nhất chứa UUID và dấu phẩy. Bạn phải đảm bảo rằng mỗi chuỗi UUID được thoát và được trích dẫn riêng lẻ, sau đó implode danh sách lại với nhau và nội suy nó thành mệnh đề IN.

    $regGUIDs = explode(',', $regGUID); 
    $regGUIDs = array_map(function ($g) { return $db->quote($g); }, $regGUIDs); 
    $regGUID = implode(',', $regGUIDs); 
    $sql = $sql . 'WHERE a.regGUID in (' . $regGUID . ') and '; 
    
  2. $ regGUID vào một mảng và thêm một tham số truy vấn cho từng phần tử trong mảng. Nội suy danh sách động của trình giữ chỗ thông số truy vấn.

    $regGUIDs = explode(',', $regGUID); 
    $params = array_fill(1, count($regGUIDs), '?'); 
    $sql = $sql . ' WHERE a.regGUID in (' . implode(',', $params) . ') and '; 
    

Bạn có thể bindValue() trong một vòng lặp cho mảng, nhưng hãy nhớ rằng các thông số khác cũng cần được ràng buộc bởi vị trí, không theo tên. PDO có lỗi khiến nó không vui khi bạn cố trộn lẫn hai kiểu tham số khác nhau trong cùng một truy vấn.

Thay vì sử dụng bindValue() tôi chỉ chuyển một mảng giá trị tham số tới PDOStatement :: execute(), dễ dàng hơn nhiều.

$paramValues = $regGUIDs; 
$paramValues[] = $game; 
$results = $stmt->execute($paramValues); 
+0

Cảm ơn bạn .. Làm việc như quyến rũ! Chỉnh sửa lỗi chính tả nhỏ trong hàm implode, mất một vài phút để nhận ra rằng cần phải có một, thay vì a. Đầu tôi đau hơn khi đập vào tường! –

+0

Cảm ơn, tôi đã sửa câu trả lời ',' trong câu trả lời ở trên. Vui mừng được giúp đỡ! –

2

Điều này thực sự đã được hỏi 1000 lần.

Báo cáo được chuẩn bị chỉ có thể chấp nhận giá trị vô hướng, không phải là các phần tùy ý của truy vấn SQL.

Bạn phải tạo biểu mẫu IN() sử dụng nhiều trình giữ chỗ, vì nhiều mục bạn phải đặt vào và sau đó liên kết từng mục một.

Để giảm bớt tác vụ này, người dùng có thể sử dụng một số chức năng trợ giúp.

Say, sử dụng SafeMysql library mã này có thể được viết như

$sql = 'SELECT * FROM events a, players b WHERE regGUID in (?a) and'; 
$sql .= ' a.playerCode=b.playerCode and a.gameCode = ?s'; 
$sql .= ' order by a.eventTime desc, a.actionCode asc'; 
$results = $db->getAll($sql,$regGUID,$game); 

Lưu ý rằng $regGUID phải là một mảng, không chuỗi và $results đã chứa tất cả các dữ liệu được yêu cầu, mà không cần bất kỳ chế biến tiếp.

1

Nội dung của $regGUID là gì? Vì bạn đang sử dụng mệnh đề in, tôi nghi ngờ một danh sách được phân tách bằng dấu phẩy.

Ràng buộc biến vào tham số không giống như thay thế chuỗi đó thành truy vấn; nó giống như nói cho MySQL biết cách sử dụng các biến PHP thực tế của bạn. Vì vậy, nếu bạn liên kết một chuỗi như '1,2,3' với thông số truy vấn, nó sẽ giữ nguyên dưới dạng một chuỗi và không được giải thích dưới dạng danh sách các số.

Do đó, nếu $regGUID là một cái gì đó giống như "'AAA1', 'BBB2'", truy vấn đầu tiên của bạn trở nên

... WHERE a.regGUID in ('AAA1', 'BBB2') ... 

nhưng truy vấn thứ hai của bạn là giống như

... WHERE a.regGUID in ('\'AAA1\', \'BBB2\'') ... 

mà là giống như nói

... WHERE a.regGUID = '\'AAA1\', \'BBB2\'' ... 
1

Khi những người khác có trạng thái, bạn chỉ có thể gắn một giá trị vô hướng duy nhất cho một trình giữ chỗ. Vì vậy, điều này có nghĩa là bạn thực sự cần một trình giữ chỗ cho mỗi giá trị trong câu lệnh IN của mình. Tôi thường làm một cái gì đó như sau. Cần lưu ý rằng mặc dù tôi không bao giờ sử dụng bindValue vì vậy nếu nó có những quy định về những điều cần phải có tài liệu tham khảo như mysqli thì dưới đây có thể cần phải được sửa đổi:

$regGUIDPlaceholders = array(); 

// prepare the placeholders 
// assume regGUID is an array - if its a string then explode on whatever to make it an array 
foreach($regGUID as $k => $v) { 
    $placeholder = ':regGUID' . $k; 
    $regGUIDPlaceholders[$key] = $value; 
} 

// prepare the IN statememnt 
$in = sprintf('IN (%s)', implode(',', array_keys($regGUIDPlaceholders))); 

$sql = 'SELECT a.eventCode, a.eventTime, a.teamCode, a.playerCode, b.lastName, b.firstName, b.number, a.xCoord, a.yCoord, a.id '; 
$sql = $sql . 'FROM events a, players b '; 

// USE the IN statement dynamically prepared above 
$sql = $sql . 'WHERE a.regGUID '. $in . ' and '; 

$sql = $sql . 'a.playerCode=b.playerCode and a.gameCode = :game order by a.eventTime desc, a.actionCode asc'; 

$stmt = $db->prepare($sql); 

// bind each GUID to its placeholder 
foreach($regGUIDPlaceholders as $placeholder => $value) { 
    $stmt->bindValue($placeholder, $value, PDO::PARAM_STR); 
} 

$stmt->bindValue(':game', $game, PDO::PARAM_STR); 
$results = $stmt->execute(); 
Các vấn đề liên quan