mysql_fetch_array () / mysql_fetch_assoc () / mysql_fetch_row () / mysql_num_rows ฯลฯ …คาดว่าพารามิเตอร์ 1 จะเป็นทรัพยากร


960

ฉันกำลังพยายามเลือกข้อมูลจากตาราง MySQL แต่ฉันได้รับข้อความแสดงข้อผิดพลาดต่อไปนี้:

mysql_fetch_array () คาดว่าพารามิเตอร์ 1 จะเป็นทรัพยากรกำหนดบูลีน

นี่คือรหัสของฉัน:

$username = $_POST['username'];
$password = $_POST['password'];

$result = mysql_query('SELECT * FROM Users WHERE UserName LIKE $username');

while($row = mysql_fetch_array($result)) {
    echo $row['FirstName'];
}

15
คุณจะได้รับข่าวสารที่มีประโยชน์มากกว่าโดยใช้ :: QUERY หรือตาย (mysql_error ());
nik

123
นอกจากนี้ยังทราบบังคับ: รหัสของคุณมีแนวโน้มที่จะฉีด SQL คุณควรตรวจสอบและ / หรือหลีกเลี่ยงการป้อนข้อมูลของผู้ใช้ mysql_real_escape_stringมีลักษณะที่ อย่าเชื่อถือข้อมูลผู้ใช้
เฟลิกซ์คลิง

7
ที่จริงแล้วรหัสของ OP จะทำให้เกิดข้อผิดพลาดทางไวยากรณ์บนเซิร์ฟเวอร์ MySQL แต่อย่างน้อยก็ไม่เสี่ยงต่อการฉีด SQL เพราะคำพูดเดียวไม่มีการแก้ไขตัวแปร
กันยายน

4
@ FelixKling ฉันรู้ว่านี่เก่ามากและน่าจะเป็นไปได้ที่แม่นยำที่สุดในขณะนี้ แต่ความคิดเห็นของคุณผิดอย่างมหันต์ในทางเดียว: mysql_real_escape_stringไม่ใช่การป้องกันการฉีด SQL ทั้งหมดและสิ้นสุด มันยังคงเสี่ยงต่อการถูกโจมตีหลายครั้ง (ไม่คุณไม่เคยบอกว่ามันสมบูรณ์แบบ แต่คุณบอกว่ามันเป็นทางออกเดียวที่จำเป็น) ตอนนี้ทางออกที่ดีที่สุดคือ PDO เท่าที่ฉันรู้
คดีของกองทุนโมนิกา

2
Gah การขยายคำถามนี้เพื่อรวม MySQLi และ PDO เป็นความคิดที่ไม่ดี พวกเขาแต่ละคนมีไวยากรณ์และข้อความแสดงข้อผิดพลาดแตกต่างกันไปเล็กน้อยและพวกเขาก็สามารถมีคำถามของตัวเองได้อย่างสมบูรณ์ การรวมทุกอย่างไว้ในคำถามสามส่วนยักษ์ทำให้ Googleable น้อยลงและบังคับให้ผู้ที่มาถึงที่นี่เพื่อลุยเนื้อหาที่ไม่เกี่ยวข้องเพื่อให้ได้สิ่งที่ต้องการ นอกจากนี้ยังเป็นโมฆะคำตอบมากมายด้านล่างและทำให้คำถามนี้ "กว้างเกินไป" ตามมาตรฐานที่เราใช้ตามปกติ ในความคิดของฉันมันเป็นระเบียบ แต่มันสายเกินไปที่จะแก้ไขในตอนนี้
Mark Amery

คำตอบ:


667

การค้นหาอาจล้มเหลวเนื่องจากสาเหตุต่าง ๆ ซึ่งในกรณีนี้ทั้ง mysql_ * และนามสกุล mysqli จะกลับมาfalseจากฟังก์ชัน / เมธอดการสืบค้นที่เกี่ยวข้อง คุณต้องทดสอบเงื่อนไขข้อผิดพลาดนั้นและจัดการตามนั้น

นามสกุล mysql_ * :

หมายเหตุฟังก์ชั่น mysql_ จะเลิกและได้ถูกลบออกใน PHP รุ่น 7

ตรวจสอบก่อนที่จะผ่านไปยัง$result mysql_fetch_arrayคุณจะพบว่าเป็นfalseเพราะแบบสอบถามล้มเหลว ดูmysql_queryเอกสารประกอบสำหรับค่าตอบแทนที่เป็นไปได้และคำแนะนำสำหรับวิธีการจัดการกับพวกเขา

$username = mysql_real_escape_string($_POST['username']);
$password = $_POST['password'];
$result = mysql_query("SELECT * FROM Users WHERE UserName LIKE '$username'");

if($result === FALSE) { 
    die(mysql_error()); // TODO: better error handling
}

while($row = mysql_fetch_array($result))
{
    echo $row['FirstName'];
}


รูปแบบขั้นตอนการขยาย mysqli :

$username = mysqli_real_escape_string($mysqli, $_POST['username']);
$result = mysqli_query($mysqli, "SELECT * FROM Users WHERE UserName LIKE '$username'");

// mysqli_query returns false if something went wrong with the query
if($result === FALSE) { 
    yourErrorHandler(mysqli_error($mysqli));
}
else {
    // as of php 5.4 mysqli_result implements Traversable, so you can use it with foreach
    foreach( $result as $row ) {
        ...

สไตล์ oo :

$username = $mysqli->escape_string($_POST['username']);
$result = $mysqli->query("SELECT * FROM Users WHERE UserName LIKE '$username'");

if($result === FALSE) { 
    yourErrorHandler($mysqli->error); // or $mysqli->error_list
}
else {
    // as of php 5.4 mysqli_result implements Traversable, so you can use it with foreach
    foreach( $result as $row ) {
      ...

ใช้คำสั่งที่เตรียมไว้:

$stmt = $mysqli->prepare('SELECT * FROM Users WHERE UserName LIKE ?');
if ( !$stmt ) {
    yourErrorHandler($mysqli->error); // or $mysqli->error_list
}
else if ( !$stmt->bind_param('s', $_POST['username']) ) {
    yourErrorHandler($stmt->error); // or $stmt->error_list
}
else if ( !$stmt->execute() ) {
    yourErrorHandler($stmt->error); // or $stmt->error_list
}
else {
    $result = $stmt->get_result();
    // as of php 5.4 mysqli_result implements Traversable, so you can use it with foreach
    foreach( $result as $row ) {
      ...

ตัวอย่างเหล่านี้แสดงให้เห็นถึงสิ่งที่ควรทำ (การจัดการข้อผิดพลาด) ไม่ใช่วิธีการทำ ไม่ควรใช้รหัสการผลิตor dieเมื่อส่ง HTML มิฉะนั้นรหัสดังกล่าว (อย่างน้อยที่สุด) จะสร้าง HTML ที่ไม่ถูกต้อง นอกจากนี้ยังมีข้อความผิดพลาดฐานข้อมูลไม่ควรที่จะแสดงให้ผู้ใช้ไม่ใช่ผู้ดูแลระบบเป็นมันเปิดเผยข้อมูลมากเกินไป


9
ถูกต้อง แต่ใช้ die () ถ้าแบบสอบถามล้มเหลวน้อยไปมาก
2ndkauboy

28
ฉันจะออกแบบกลไกการจัดการข้อผิดพลาดทั้งหมดสำหรับ OP แต่ตัดสินใจว่าอาจเกินขอบเขตคำตอบของฉัน
Edward Dale

@ scompt.com ใช่มันยังครอบคลุมอยู่ในคำตอบอื่น ๆ อีกมากมาย ฉันเดาว่าฉันกำลังทำประเด็นที่ว่าเนื่องจากนี่เป็นคำตอบที่ได้รับการยอมรับสำหรับคำถามที่มองเห็นได้นอกเหนือจากคำแนะนำ (ยอดเยี่ยม) เกี่ยวกับวิธีการตรวจจับข้อผิดพลาดในอนาคตอย่างถูกต้องควร (IMHO) ตอบคำถามเฉพาะจริง ๆ อธิบายสาเหตุที่เกิดข้อผิดพลาดในกรณีนี้)
Sepster

2
แทนการที่คุณสามารถใช้if($result === FALSE) if(! $result)แก้ไขฉันถ้าฉันผิด
anestv

1
mysql_query (): นามสกุล mysql เลิกใช้แล้วและจะถูกลบออกในอนาคต: ใช้ mysqli
Greg

165

ข้อความแสดงข้อผิดพลาดนี้จะปรากฏขึ้นเมื่อคุณมีข้อผิดพลาดในแบบสอบถามของคุณซึ่งทำให้ล้มเหลว มันจะประจักษ์เองเมื่อใช้:

  • mysql_fetch_array/mysqli_fetch_array()
  • mysql_fetch_assoc()/mysqli_fetch_assoc()
  • mysql_num_rows()/mysqli_num_rows()

หมายเหตุ : ข้อผิดพลาดนี้จะไม่ปรากฏหากไม่มีแถวที่ได้รับผลกระทบจากแบบสอบถามของคุณ เฉพาะแบบสอบถามที่มีไวยากรณ์ที่ไม่ถูกต้องเท่านั้นที่จะสร้างข้อผิดพลาดนี้

ขั้นตอนการแก้ไขปัญหา

  • ตรวจสอบให้แน่ใจว่าคุณได้กำหนดค่าเซิร์ฟเวอร์การพัฒนาเพื่อแสดงข้อผิดพลาดทั้งหมด คุณสามารถทำได้โดยการวางไว้ที่ด้านบนของไฟล์หรือในไฟล์ปรับแต่งของคุณ:error_reporting(-1);ของคุณ: หากคุณมีข้อผิดพลาดทางไวยากรณ์สิ่งนี้จะชี้ให้พวกคุณเห็น

  • mysql_error()ใช้mysql_error()จะรายงานข้อผิดพลาดใด ๆ ที่ MySQL พบขณะทำการสืบค้น

    ตัวอย่างการใช้งาน:

    mysql_connect($host, $username, $password) or die("cannot connect"); 
    mysql_select_db($db_name) or die("cannot select DB");
    
    $sql = "SELECT * FROM table_name";
    $result = mysql_query($sql);
    
    if (false === $result) {
        echo mysql_error();
    }
  • เรียกใช้แบบสอบถามของคุณจากบรรทัดคำสั่ง MySQL หรือเครื่องมือเช่นphpMyAdmin หากคุณมีข้อผิดพลาดทางไวยากรณ์ในข้อความค้นหาของคุณสิ่งนี้จะบอกคุณว่ามันคืออะไร

  • ตรวจสอบให้แน่ใจว่าคำพูดของคุณถูกต้อง คำพูดที่หายไปรอบ ๆ แบบสอบถามหรือค่าอาจทำให้แบบสอบถามล้มเหลว

  • ตรวจสอบให้แน่ใจว่าคุณกำลังหลบหนีคุณค่าของคุณ เครื่องหมายคำพูดในแบบสอบถามของคุณอาจทำให้แบบสอบถามล้มเหลว (และทำให้คุณเปิดการแทรก SQL) ใช้mysql_real_escape_string()เพื่อหลีกเลี่ยงการป้อนข้อมูลของคุณ

  • ตรวจสอบให้แน่ใจว่าคุณไม่ได้ผสมmysqli_*และmysql_*ฟังก์ชั่น มันไม่เหมือนกันและไม่สามารถใช้ร่วมกันได้ (หากคุณกำลังจะเลือกหนึ่งหรืออื่น ๆ ติดกับmysqli_*ดูด้านล่างสำหรับสาเหตุ)

เคล็ดลับอื่น ๆ

mysql_*ไม่ควรใช้ฟังก์ชั่นสำหรับรหัสใหม่ พวกเขาจะรักษาไม่และชุมชนได้เริ่มกระบวนการการเลิกใช้ แต่คุณควรเรียนรู้เกี่ยวกับงบเตรียมและการใช้อย่างใดอย่างหนึ่งPDOหรือMySQLi หากคุณไม่สามารถตัดสินใจได้บทความนี้จะช่วยในการเลือก หากคุณสนใจที่จะเรียนรู้และนี่คือการกวดวิชา PDO ดี


1
ให้คำถามนี้ในวันนี้stackoverflow.com/q/43804651/1415724และสิ่งอื่นที่คล้ายคลึงกันเมื่อเร็ว ๆ นี้ ฉันคิดว่ามันอาจจะคุ้มค่าที่จะอัปเดตคำตอบของคุณเพื่อให้มีบางอย่างเช่น"ข้อผิดพลาดอาจเกิดจากการไม่ดำเนินการค้นหาด้วยmysql_query()/ mysqli_query($connection)etc" ; ความคิด? เนื่องจากไม่มีคำตอบอื่น ๆ ในคำถาม & คำตอบนี้
Funk Forty Niner

111

เกิดข้อผิดพลาดที่นี่เนื่องจากการใช้อัญประกาศเดี่ยว ( ') คุณสามารถใส่คำถามของคุณเช่นนี้:

mysql_query("
SELECT * FROM Users 
WHERE UserName 
LIKE '".mysql_real_escape_string ($username)."'
");

มันใช้mysql_real_escape_stringสำหรับป้องกันการฉีด SQL แม้ว่าเราควรใช้ MySQLi หรือ PDO_MYSQL extension สำหรับ PHP เวอร์ชั่นอัพเกรด (PHP 5.5.0 และใหม่กว่า) แต่สำหรับเวอร์ชั่นเก่าmysql_real_escape_stringนั้นจะใช้กลอุบาย


5
ทำไมเพิ่มเสียงรบกวนด้วยการต่อสตริงแทนการใส่ตัวแปรในสตริงการสืบค้น
Matteo Riva

1
@Matteo Riva Yeah แต่ฉันคิดว่านี่เป็นวิธีที่สะอาดกว่าเล็กน้อยในการแยกตัวแปรออกจากสตริง :)
nik

60

ตามที่scompt.comอธิบายไว้แบบสอบถามอาจล้มเหลว ใช้รหัสนี้เพื่อรับข้อผิดพลาดของแบบสอบถามหรือผลลัพธ์ที่ถูกต้อง:

$username = $_POST['username'];
$password = $_POST['password'];

$result = mysql_query("
SELECT * FROM Users 
WHERE UserName LIKE '".mysql_real_escape_string($username)."'
");

if($result)
{
    while($row = mysql_fetch_array($result))
    {
        echo $row['FirstName'];
    }
} else {
    echo 'Invalid query: ' . mysql_error() . "\n";
    echo 'Whole query: ' . $query; 
}

ดูเอกสารประกอบสำหรับmysql_query()ข้อมูลเพิ่มเติม

ข้อผิดพลาดที่เกิดขึ้นจริงคือคำพูดเดียวเพื่อให้ตัวแปร$usernameไม่ได้แยกวิเคราะห์ แต่คุณควรใช้mysql_real_escape_string($username)เพื่อหลีกเลี่ยงการฉีด SQL


52

$usernameคำพูดใส่รอบ ค่าสตริงซึ่งต่างจากค่าตัวเลขต้องอยู่ในเครื่องหมายคำพูด

$result = mysql_query("SELECT * FROM Users WHERE UserName LIKE '$username'");

นอกจากนี้ยังมีจุดในการใช้ไม่มีLIKEเงื่อนไขถ้าคุณไม่ได้ใช้สัญลักษณ์แทน: ถ้าคุณต้องการการใช้งานที่ถูกต้องตรงแทน=LIKE


1
และจะเป็นอย่างไรหากชื่อผู้ใช้ $ คือ: "'; DROP TABLES;" ? นั่นคือข้อดีของการใช้งบที่เตรียมไว้และค่าผูกพันซึ่งฉันคิดว่าผู้ถามต้องการเก็บไว้
HoldOffHunger

42

โปรดตรวจสอบอีกครั้งว่าฐานข้อมูลที่เลือกไม่ใช่เพราะบางครั้งฐานข้อมูลไม่ได้ถูกเลือก

ตรวจสอบ

mysql_select_db('database name ')or DIE('Database name is not available!');

ก่อนการสืบค้น MySQL แล้วไปที่ขั้นตอนต่อไป

$result = mysql_query('SELECT * FROM Users WHERE UserName LIKE $username');

f($result === FALSE) {
    die(mysql_error());

40

รหัสของคุณควรเป็นแบบนี้

$username = $_POST['username'];
$password = $_POST['password'];
$query = "SELECT * FROM Users WHERE UserName LIKE '$username'";
echo $query;
$result = mysql_query($query);

if($result === FALSE) {
    die(mysql_error("error message for the user")); 
}

while($row = mysql_fetch_array($result))
{
    echo $row['FirstName'];
}

เมื่อเสร็จแล้วคุณจะได้รับแบบสอบถามที่พิมพ์บนหน้าจอ ลองใช้แบบสอบถามนี้บนเซิร์ฟเวอร์ของคุณและดูว่ามันสร้างผลลัพธ์ที่ต้องการ ข้อผิดพลาดส่วนใหญ่อยู่ในแบบสอบถาม ส่วนที่เหลือของรหัสถูกต้อง


3
อย่าใช้รหัสนี้ มันเปิดกว้างสำหรับการโจมตีการฉีด SQL
แบรด

34
$result = mysql_query('SELECT * FROM Users WHERE UserName LIKE $username');

คุณกำหนดสตริงโดยใช้อัญประกาศเดี่ยวและ PHP ไม่แยกวิเคราะห์สตริงที่คั่นด้วยเครื่องหมายคำพูดเดี่ยว เพื่อให้ได้การแก้ไขตัวแปรคุณจะต้องใช้เครื่องหมายคำพูดคู่หรือการต่อสตริง (หรือรวมกันที่) ดูhttp://php.net/manual/th/language.types.string.phpสำหรับข้อมูลเพิ่มเติม

นอกจากนี้คุณควรตรวจสอบว่า mysql_query ส่งคืนทรัพยากรผลลัพธ์ที่ถูกต้องมิฉะนั้น fetch_ *, num_rows ฯลฯ จะไม่ทำงานกับผลลัพธ์เนื่องจากไม่ใช่ผลลัพธ์! IE:

$username = $_POST['username'];
$password = $_POST['password'];
$result = mysql_query('SELECT * FROM Users WHERE UserName LIKE $username');

if( $result === FALSE ) {
   trigger_error('Query failed returning error: '. mysql_error(),E_USER_ERROR);
} else {
   while( $row = mysql_fetch_array($result) ) {
      echo $row['username'];
   }
}

http://us.php.net/manual/th/function.mysql-query.phpสำหรับข้อมูลเพิ่มเติม


2
อย่าใช้รหัสนี้แม้ว่าคุณจะเพิ่มคำพูด มันเปิดกว้างสำหรับการโจมตีการฉีด SQL
แบรด

33

แบบสอบถามนี้ควรใช้งานได้:

$result = mysql_query("SELECT * FROM Users WHERE UserName LIKE '%$username%'");
while($row = mysql_fetch_array($result))
{
    echo $row['FirstName'];
}

ปัญหาคืออัญประกาศเดี่ยวดังนั้นแบบสอบถามของคุณจึงล้มเหลวและส่งกลับค่า FALSE และขณะที่ลูปของคุณไม่สามารถดำเนินการได้ การใช้% ช่วยให้คุณสามารถจับคู่ผลลัพธ์ที่มีสตริงของคุณ (เช่น SomeText- $ username-SomeText)

นี่เป็นเพียงคำตอบสำหรับคำถามของคุณคุณควรใช้สิ่งต่าง ๆ ที่กล่าวถึงในโพสต์อื่น ๆ : การจัดการข้อผิดพลาดใช้สตริง escape (ผู้ใช้สามารถพิมพ์อะไรก็ได้ในฟิลด์และคุณต้องแน่ใจว่าไม่ใช่รหัสโดยพลการ) ใช้PDOแทน mysql_connect ซึ่งตอนนี้ได้รับการลงนามแล้ว


28
$username = $_POST['username'];
$password = $_POST['password'];
$result = mysql_query("SELECT * FROM Users WHERE UserName LIKE '%$username%'") or die(mysql_error());

while($row = mysql_fetch_array($result))
{
    echo $row['FirstName'];
}

บางครั้งการระงับแบบสอบถามเป็น @mysql_query(your query);


2
อย่าใช้รหัสนี้ มันเปิดกว้างสำหรับการโจมตีการฉีด SQL
แบรด

27

หากคุณลองทุกอย่างที่นี่และมันไม่ทำงานคุณอาจต้องการตรวจสอบการเปรียบเทียบฐานข้อมูล MySQL ของคุณ ฉันถูกตั้งค่าให้การเปรียบเทียบสวีเดน จากนั้นฉันเปลี่ยนมันเป็นutf8_general_ciและทุกอย่างเพียงคลิกเป็นเกียร์


25
$query = "SELECT Name,Mobile,Website,Rating FROM grand_table order by 4";

while( $data = mysql_fetch_array($query))
{
    echo("<tr><td>$data[0]</td><td>$data[1]</td><td>$data[2]</td><td>$data[3]</td></tr>");      
}

แทนที่จะใช้แบบสอบถามแบบ WHERE คุณสามารถใช้แบบสอบถาม ORDER BY นี้ได้ มันดีกว่านี้มากสำหรับการใช้แบบสอบถาม

ฉันได้ทำแบบสอบถามนี้และไม่ได้รับข้อผิดพลาดเช่นพารามิเตอร์หรือบูลีน


จำไว้ว่าให้ใช้htmlspecialchars()เมื่อใช้ข้อมูลโดยพลการในบริบทของ HTML มิฉะนั้นคุณจะเสี่ยงต่อการสร้าง HTML ที่ถูกต้องเมื่อมีการใช้อักขระที่สงวนไว้ในข้อมูล
แบรด

25

ลองใช้งานต้องใช้งานไม่เช่นนั้นคุณจะต้องพิมพ์ข้อผิดพลาดเพื่อระบุปัญหาของคุณ

$username = $_POST['username'];
$password = $_POST['password'];

$sql = "SELECT * from Users WHERE UserName LIKE '$username'";
$result = mysql_query($sql,$con);

while($row = mysql_fetch_array($result))
{
    echo $row['FirstName'];
}

8
1) เปิดกว้างสำหรับการฉีด SQL 2) ไม่รวมการจัดการข้อผิดพลาดซึ่งทำให้เกิดข้อผิดพลาดในกรณีของ OP
หลอกลวง

+1 @deceze ใช่มันเปิดกว้าง แต่ไม่มากไปกว่านั้นรหัส OP หรือรหัสของผู้ตอบรับที่ยอมรับ ;-) และมันก็ไม่ใช่การจัดการข้อผิดพลาดในรหัสของ OP ที่ทำให้เกิดข้อผิดพลาด ... มันเป็นข้อผิดพลาดและคำตอบนี้พยายามอย่างน้อยแก้ปัญหานั้น คำพูดรอบตัวอักษรสตริงในการLIKEแสดงออก)
Sepster

1
+1 โปรดเพิ่มช่องว่างระหว่าง LIKE และ '$ ชื่อผู้ใช้' ส่วนที่เหลือดูเหมือนว่าจะใช้ได้ยกเว้นการฉีด SQL ทำไมไม่ใช้ = แทนชื่อผู้ใช้โอเปอเรเตอร์ LIKE ต้องตรงกันทุก
ประการ

21

อาจมีเหตุผลสองประการ:

  1. คุณได้เปิดการเชื่อมต่อกับฐานข้อมูลก่อนที่จะเรียกใช้ฟังก์ชัน mysql_query หรือไม่? ฉันไม่เห็นว่าในรหัสของคุณ ใช้ mysql_connect ก่อนทำแบบสอบถาม ดูphp.net/manual/en/function.mysql-connect.php

  2. ตัวแปรชื่อผู้ใช้ $ถูกใช้ภายในสตริงคำพูดเดียวดังนั้นค่าของมันจะไม่ถูกประเมินภายในแบบสอบถาม แบบสอบถามจะล้มเหลวอย่างแน่นอน

ประการที่สามโครงสร้างของแบบสอบถามมีแนวโน้มที่จะฉีด SQL คุณอาจใช้คำสั่งที่เตรียมไว้เพื่อหลีกเลี่ยงภัยคุกคามความปลอดภัยนี้


20

ลองรหัสต่อไปนี้ มันอาจทำงานได้ดี

$username = $_POST['username'];
$password = $_POST['password'];
$result = mysql_query("SELECT * FROM Users WHERE UserName ='$username'");

while($row = mysql_fetch_array($result))
{
    echo $row['FirstName'];
}

4
รหัสนี้อยู่ภายใต้การฉีด SQL และไม่ควรใช้
แบรด

15

config.phpไปที่ ผมมีปัญหาเดียวกัน. ตรวจสอบชื่อผู้ใช้และรหัสผ่านและเลือก sql เป็นชื่อเดียวกับการกำหนดค่า


15

อย่าใช้ฟังก์ชั่น mysql_ * ที่แยกจากกัน (depricated ใน php 5.5 จะถูกลบออกใน php 7) และคุณสามารถทำสิ่งนี้ด้วยmysqliหรือpdo

นี่คือแบบสอบถามแบบใช้เลือกข้อมูลที่สมบูรณ์

<?php
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "myDB";

// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
} 

$sql = "SELECT id, firstname, lastname FROM MyGuests";
$result = $conn->query($sql);

if ($result->num_rows > 0) {
    // output data of each row
    while($row = $result->fetch_assoc()) {
        // code here 
    }
} else {
    echo "0 results";
}
$conn->close();
?>

โพสต์ของคุณไม่ได้จัดการกับปัญหาที่ระบุโดยคำถามซึ่งเป็นคำถามที่ไม่ถูกต้องและการรายงานข้อผิดพลาดอย่างไม่แน่นอน โพสต์นี้ปิดหัวข้อ
Paul Spiegel

14
<?php
    $username = $_POST['username'];
    $password = $_POST['password'];
    $result = mysql_query("SELECT * FROM Users WHERE UserName LIKE '".$username."'");

    while($row = mysql_fetch_array($result))
    {
        echo $row['FirstName'];
    }
?>

และหากมีผู้ใช้ที่มีชื่อผู้ใช้ที่ไม่ซ้ำกันคุณสามารถใช้ "=" สำหรับสิ่งนั้น ไม่จำเป็นต้องชอบ

คำถามของคุณจะเป็น:

mysql_query("SELECT * FROM Users WHERE UserName ='".$username."'");

3
รหัสนี้เปิดกว้างสำหรับการฉีด SQL และไม่ควรใช้
แบรด

@AnujGarg รหัสนี้จะนำเข้าโดยตรงและเชื่อมต่อลงในแบบสอบถาม บางคนสามารถเขียน SQL ของตนเองลงในข้อมูลการโพสต์usernameและจะถูกดำเนินการ
แบรด

ดังนั้นสิ่งที่จะใช้เพื่อป้องกันรหัสจากการฉีด SQL?
Anuj Garg

14

รวมตัวแปรสตริงการเชื่อมต่อก่อนแบบสอบถาม MySQL ตัวอย่างเช่น$conntในรหัสนี้:

$results = mysql_query($connt, "SELECT * FROM users");

1
สิ่งนี้ไม่ได้แก้ไขปัญหาในคำถาม มันก็ผิดและจะทำให้เกิดข้อผิดพลาดอีก
Paul Spiegel

12

เมื่อใดก็ตามที่คุณได้รับ ...

"คำเตือน: mysqli_fetch_object () คาดว่าพารามิเตอร์ 1 จะเป็น mysqli_result โดยกำหนดบูลีน"

... อาจเป็นเพราะมีปัญหากับแบบสอบถามของคุณ prepare()หรือquery()อาจส่งคืนFALSE(บูลีน) แต่ความล้มเหลวนี้ข้อความทั่วไปไม่ปล่อยให้คุณมากในทางของเบาะแส คุณจะทราบได้อย่างไรว่ามีข้อผิดพลาดเกิดขึ้นกับข้อความค้นหาของคุณอย่างไร คุณถาม !

ก่อนอื่นตรวจสอบให้แน่ใจว่าการรายงานข้อผิดพลาดเปิดอยู่และมองเห็นได้: เพิ่มสองบรรทัดต่อไปนี้ที่ด้านบนของไฟล์ทันทีหลังจากเปิด<?phpแท็ก:

error_reporting(E_ALL);
ini_set('display_errors', 1);

หากการรายงานข้อผิดพลาดของคุณได้รับการตั้งค่าใน php.ini คุณจะไม่ต้องกังวลเกี่ยวกับเรื่องนี้ เพียงให้แน่ใจว่าคุณจัดการข้อผิดพลาดอย่างสง่างามและไม่เปิดเผยสาเหตุที่แท้จริงของปัญหาใด ๆ ให้กับผู้ใช้ของคุณ การเปิดเผยสาเหตุที่แท้จริงต่อสาธารณะอาจเป็นคำเชิญสลักทองสำหรับผู้ที่ต้องการทำอันตรายต่อไซต์และเซิร์ฟเวอร์ของคุณ หากคุณไม่ต้องการส่งข้อผิดพลาดไปยังเบราว์เซอร์คุณสามารถตรวจสอบบันทึกข้อผิดพลาดของเว็บเซิร์ฟเวอร์ได้ตลอดเวลา สถานที่เข้าสู่ระบบจะแตกต่างจากเซิร์ฟเวอร์เช่นเซิร์ฟเวอร์บน Ubuntu /var/log/apache2/error.logบันทึกข้อผิดพลาดมักจะตั้งอยู่ที่ หากคุณกำลังตรวจสอบบันทึกข้อผิดพลาดในสภาพแวดล้อม Linux คุณสามารถใช้tail -f /path/to/logในหน้าต่างคอนโซลเพื่อดูข้อผิดพลาดที่เกิดขึ้นแบบเรียลไทม์ .... หรือตามที่คุณทำ

เมื่อคุณถูกยกกำลังสองไปกับการรายงานข้อผิดพลาดมาตรฐานการเพิ่มการตรวจสอบข้อผิดพลาดในการเชื่อมต่อฐานข้อมูลของคุณและแบบสอบถามจะให้รายละเอียดเพิ่มเติมเกี่ยวกับปัญหาที่เกิดขึ้น ดูตัวอย่างที่ชื่อคอลัมน์ไม่ถูกต้อง ก่อนรหัสที่ส่งกลับข้อผิดพลาดร้ายแรงทั่วไป:

$sql = "SELECT `foo` FROM `weird_words` WHERE `definition` = ?";
$query = $mysqli->prepare($sql)); // assuming $mysqli is the connection
$query->bind_param('s', $definition);
$query->execute();

ข้อผิดพลาดทั่วไปและไม่เป็นประโยชน์กับคุณในการแก้ไขสิ่งที่เกิดขึ้น

กับคู่ของบรรทัดที่มากขึ้นของรหัสที่คุณจะได้รับข้อมูลรายละเอียดมากที่คุณสามารถใช้เพื่อแก้ปัญหาทันที ตรวจสอบprepare()คำแถลงเกี่ยวกับความจริงและหากเป็นเรื่องที่ดีคุณสามารถดำเนินการผูกมัดและดำเนินการต่อได้

$sql = "SELECT `foo` FROM `weird_words` WHERE `definition` = ?";
if($query = $mysqli->prepare($sql)) { // assuming $mysqli is the connection
    $query->bind_param('s', $definition);
    $query->execute();
    // any additional code you need would go here.
} else {
    $error = $mysqli->errno . ' ' . $mysqli->error; // 1054 Unknown column 'foo' in 'field list'
    // handle error
}

หากมีสิ่งผิดปกติคุณสามารถพ่นข้อความแสดงข้อผิดพลาดออกซึ่งนำคุณไปสู่ปัญหาโดยตรง ในกรณีนี้ไม่มีfooคอลัมน์ในตารางการแก้ปัญหาเป็นเรื่องเล็กน้อย

หากคุณเลือกคุณสามารถรวมการตรวจสอบนี้ในฟังก์ชั่นหรือคลาสและขยายโดยการจัดการข้อผิดพลาดอย่างสง่างามตามที่กล่าวไว้ก่อนหน้านี้


2
คุณจะเขียนได้อย่างไร "ตรวจสอบให้แน่ใจว่าคุณจัดการข้อผิดพลาดอย่างสง่างามและไม่เปิดเผยสาเหตุที่แท้จริงของปัญหาใด ๆ ต่อผู้ใช้ของคุณ" และecho $error;ในหนึ่งโพสต์?
Paul Spiegel

ขอบคุณสำหรับ heads up @ PaulSpiegel เป็นเวลานานแล้วที่ฉันเขียนหรือมาหาคำตอบอีกครั้งและพลาดไปว่าฉันทิ้งเสียงสะท้อนไว้ที่นั่น
Jay Blanchard

11
<?php
      $username = $_POST['username'];
       $password = $_POST['password'];

     $result = mysql_query("SELECT * FROM Users WHERE UserName LIKE '".mysql_real_escape_string($username)."'")or die(mysql_error());
while($row=mysql_fetch_array($result))
  {
 echo $row['FirstName'];
 }
 ?>

11

ลองสิ่งนี้

$username = $_POST['username'];
$password = $_POST['password'];
$result = mysqli_query('SELECT * FROM Users WHERE UserName LIKE $username');

if($result){
while($row = mysqli_fetch_array($result))
{
    echo $row['FirstName'];
}
}

4
@panjehra mysql_ * ไม่ได้รับการควบคุมในขณะนี้และจะถูกลบออกจาก php 7 ใช้ mysqli_ * แทน
Manoj Kumar

9

ก่อนอื่นให้ตรวจสอบการเชื่อมต่อของคุณกับฐานข้อมูล เชื่อมต่อสำเร็จหรือไม่

ถ้ามันเสร็จแล้วหลังจากนั้นฉันได้เขียนรหัสนี้และมันทำงานได้ดี:

if (isset($_GET['q1mrks']) && isset($_GET['marks']) && isset($_GET['qt1'])) {
    $Q1mrks = $_GET['q1mrks'];
    $marks = $_GET['marks'];
    $qt1 = $_GET['qt1'];

    $qtype_qry = mysql_query("
        SELECT *
        FROM s_questiontypes
        WHERE quetype_id = '$qt1'
    ");
    $row = mysql_fetch_assoc($qtype_qry);
    $qcode = $row['quetype_code'];

    $sq_qry = "
        SELECT *
        FROM s_question
        WHERE quetype_code = '$qcode'
        ORDER BY RAND() LIMIT $Q1mrks
    ";
    $sq_qry = mysql_query("
        SELECT *
        FROM s_question
        WHERE quetype_code = '$qcode'
        LIMIT $Q1mrks
    ");
    while ($qrow = mysql_fetch_array($sq_qry)) {
        $qm = $qrow['marks'] . "<br />";
        $total += $qm . "<br />";
    }
    echo $total . "/" . $marks;
}

2
อย่าใช้รหัสนี้ มันเปิดกว้างสำหรับการโจมตีการฉีด SQL
แบรด

9

ตรวจสอบให้แน่ใจว่าคุณไม่ได้ปิดฐานข้อมูลโดยใช้ db_close () ก่อนเรียกใช้แบบสอบถามของคุณ:

หากคุณใช้หลายแบบสอบถามในสคริปต์แม้ว่าคุณจะรวมหน้าอื่น ๆ ที่มีการสืบค้นหรือการเชื่อมต่อฐานข้อมูลก็อาจเป็นไปได้ว่าที่ใดก็ตามที่คุณใช้ db_close () ที่จะปิดการเชื่อมต่อฐานข้อมูลของคุณ ไม่ทำผิดพลาดในสคริปต์ของคุณ


8

หากคุณไม่มีข้อผิดพลาด MySQL ปรากฏขึ้นขณะตรวจสอบให้แน่ใจว่าคุณสร้างตารางฐานข้อมูลของคุณอย่างถูกต้อง เรื่องนี้เกิดขึ้นกับฉัน ค้นหาเครื่องหมายจุลภาคหรือคำพูดที่ไม่ต้องการ


7

ตรวจสอบการเชื่อมต่อของคุณก่อน

ถ้าคุณต้องการดึงค่าที่แน่นอนจากฐานข้อมูลคุณควรเขียน:

$username = $_POST['username'];
$password = $_POST['password'];
$result = mysql_query("SELECT * FROM Users WHERE UserName =`$usernam`");

หรือคุณต้องการดึงข้อมูลLIKEประเภทของค่าจากนั้นคุณควรเขียน:

$result = mysql_query("SELECT * FROM Users WHERE UserName LIKE '%$username%'");

3
รหัสนี้เปิดกว้างสำหรับการฉีด SQL และไม่ควรใช้
แบรด

6

นอกจากนี้คุณยังสามารถตรวจสอบว่าสภาพอากาศ$resultไม่เป็นเช่นนั้นได้ก่อนที่จะเรียกใช้อาร์เรย์ดึงข้อมูล

$username = $_POST['username'];
$password = $_POST['password'];
$result = mysql_query('SELECT * FROM Users WHERE UserName LIKE $username');
if(!$result)
{
     echo "error executing query: "+mysql_error(); 
}else{
       while($row = mysql_fetch_array($result))
       {
         echo $row['FirstName'];
       }
}

3
อย่าใช้รหัสนี้ มันเปิดกว้างสำหรับการโจมตีการฉีด SQL
แบรด

แต่ถ้ารหัสใช้งานได้ฉันคิดว่าคุณควรแก้ไขรหัสและป้อนตัวกรองที่จำเป็นแทนการตรวจสอบรหัส
user28864

การใช้งานตัวกรองอย่างง่ายจะไม่แก้ไขสิ่งที่ผิดปกติกับรหัสนี้ ทางออกที่ดีที่สุดคือการใช้แบบสอบถามแบบเตรียม / พารามิเตอร์กับ PDO หรือคล้ายกัน ฉันไม่เห็นจุดใดในการแก้ไขเนื่องจากคำตอบที่ถูกต้องได้ถูกโพสต์ที่นี่แล้ว เป็นการดีที่คำตอบนี้จะถูกลบ อย่างไรก็ตามคุณสามารถแก้ไขคำตอบของคุณได้และฉันจะลงคะแนนถ้ามันถูกต้อง
แบรด

ถ้าคุณรู้สึกว่าคำตอบนั้นไม่คุ้มค่าที่จะพิจารณาคุณสามารถไปข้างหน้าและอ่านมันได้ อย่างไรก็ตามฉันคิดว่าจุดรวมของชุมชนนี้คือการแบ่งปันและให้ความรู้ หากคุณมีบางอย่างที่จะแบ่งปันแทนที่จะแสดงและนำคนออกไป
user28864

2
คุณถูกต้องจุดรวมของชุมชนนี้คือการแบ่งปันความรู้ นั่นเป็นเหตุผลที่เพิ่มคำอธิบายด้วย downvote ของฉันและอธิบายเพิ่มเติมว่าทำไมคำแนะนำตัวกรองของคุณไม่เพียงพอ ฉันอยากเตือนคุณมากพร้อมกับคนอื่น ๆ ที่พบคำตอบของคุณว่ารหัสข้างต้นไม่ปลอดภัย มันจะดีกว่าสำหรับทุกคนที่จะเรียนรู้วิธีการที่ถูกต้องมากกว่าการขยายเวลารหัสที่ไม่ดี และฉันไม่สามารถลบคำตอบของคุณและฉันก็ไม่ได้ขึ้นอยู่กับคุณถ้าคุณเลือกที่จะทำ
แบรด

4

โดยปกติแล้วจะมีข้อผิดพลาดเกิดขึ้นเมื่อฐานข้อมูลของคุณล้มเหลวดังนั้นโปรดเชื่อมต่อฐานข้อมูลของคุณหรือเพื่อรวมไฟล์ฐานข้อมูล

include_once(db_connetc.php');

หรือ

// Create a connection
$connection = mysql_connect("localhost", "root", "") or die(mysql_error());

//Select database
mysql_select_db("db_name", $connection) or die(mysql_error());

$employee_query = "SELECT * FROM employee WHERE `id` ='".$_POST['id']."'";

$employee_data = mysql_query($employee_query);

if (mysql_num_rows($employee_data) > 0) {

    while ($row = mysql_fetch_array($employee_data)){
        echo $row['emp_name'];
    } // end of while loop
} // end of if
  • แนวทางปฏิบัติที่ดีที่สุดคือการเรียกใช้แบบสอบถามใน sqlyog แล้วคัดลอกลงในรหัสหน้าของคุณ
  • เก็บแบบสอบถามของคุณในตัวแปรเสมอแล้วสะท้อนตัวแปรนั้น mysql_query($query_variable);จากนั้นผ่านไป

2
1) คุณไม่รู้ว่าฉันมีหรือยังไม่ลงคะแนนในคำตอบใด ๆ ที่นี่ขึ้นหรือลง 2) ตามที่ฉันอธิบายในความคิดเห็นแรกของฉัน; คำตอบของคุณไม่อ้างอิงปัญหา ( บูลส่งผ่านไปยัง mysql_fetch_array ) และคุณมีข้อผิดพลาดทางไวยากรณ์
ฟิล

2
คุณมีเครื่องหมายคำพูดที่ไม่ถูกต้องทั้งในตัวอย่างโค้ดของคุณ การเน้นไวยากรณ์ที่นำไปใช้กับบล็อกโค้ดที่สองของคุณคือสิ่งที่ผิดพลาด
Phil

4
รหัสนี้อยู่ภายใต้การฉีด SQL และไม่ควรใช้ @EngrZardari หากคุณใช้รหัสนี้ในระบบการผลิตของคุณคุณถูกแฮ็กอย่างไม่ต้องสงสัยและควรแก้ไขสถานการณ์การซื้อโดยใช้แบบสอบถามที่เตรียม / พารามิเตอร์ด้วย PDO หรือที่คล้ายกัน มีบ็อตที่มีการทดสอบอัตโนมัติสำหรับช่องโหว่ดังกล่าว
แบรด

1
@EngrZardari เกี่ยวกับคุณ"ไม่มีข้อผิดพลาดใด ๆ ฉันได้วางโค้ดที่ฉันใช้อยู่ในปัจจุบัน" ความคิดเห็นด้านบน มีคำพูดที่หายไปในแบบสอบถามที่ฉันแก้ไข ที่จะมีข้อผิดพลาดในการแยกวิเคราะห์ (PHP)
Funk Forty Niner

2

ลองใช้รหัสนี้ใช้งานได้ดี

กำหนดตัวแปรโพสต์ให้กับตัวแปร

   $username = $_POST['uname'];

   $password = $_POST['pass'];

  $result = mysql_query('SELECT * FROM userData WHERE UserName LIKE $username');

if(!empty($result)){

    while($row = mysql_fetch_array($result)){
        echo $row['FirstName'];
     }
}

3
รหัสนี้ขึ้นอยู่กับการโจมตีของการฉีด SQL และไม่ควรใช้
แบรด

1

เนื่องจากชื่อผู้ใช้ $ เป็นตัวแปร php เราจำเป็นต้องผ่านมันเป็นสตริงไปยัง mysqli ดังนั้นเนื่องจากในการสืบค้นคุณเริ่มต้นด้วยคำพูดเดียวเราจะใช้เครื่องหมายคำพูดคู่, คำพูดเดี่ยวและ fullstop สำหรับจุดประสงค์ในการเชื่อมต่อ ("'. '") ถ้าคุณเริ่มด้วยเครื่องหมายคำพูดคู่คุณจะต้องย้อนกลับเครื่องหมายคำพูด ('". $ username. "')

$username = $_POST['username'];
$password = $_POST['password'];
$result = mysql_query('SELECT * FROM Users WHERE UserName LIKE "'.$username.'"');

while($row = mysql_fetch_array($result))
     {
      echo $row['FirstName'];
     }

$username = $_POST['username'];
$password = $_POST['password'];
$result = mysql_query("SELECT * FROM Users WHERE UserName LIKE '".$username."' ");

while($row = mysql_fetch_array($result))
     {
      echo $row['FirstName'];
     }

แต่การใช้ Mysql ได้ลดค่าลงมากใช้ PDO แทนมันง่าย แต่ปลอดภัยมาก


แต่การใช้ Mysql ได้ลดลง คุณสามารถใช้ PDO แทน ให้ฉันให้ตัวอย่างเข้าสู่ระบบ
Dennis Kiptugen

2
รหัสผ่านไม่ควรถูกเก็บไว้ในรูปแบบข้อความล้วนใช้ประโยชน์จาก fucntions ที่ PHP สร้างขึ้นเพื่อจัดการกับการแฮ็กรหัสผ่านและการยืนยันรหัสผ่านที่ถูกแฮช!
SpacePhoenix
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.