การเปรียบเทียบสตริงโดยใช้ '==' กับ 'strcmp ()'


334

ดูเหมือนว่า===ผู้ประกอบการของ PHP เป็นกรณี ๆ ไป ดังนั้นมีเหตุผลที่จะใช้strcmp()หรือไม่

การทำสิ่งต่อไปนี้ปลอดภัยหรือไม่

if ($password === $password2) { ... }

10
การคำนึงถึงตัวพิมพ์ใหญ่ - เล็กเกี่ยวข้องกับstrcmpอะไร
kennytm

1
@KennyTM: คำนึงถึงขนาดตัวstrcmpพิมพ์ ในบางภาษาเช่น VB การเปรียบเทียบสตริงอาจไม่เป็นเช่นนั้นและจะให้ผลลัพธ์ที่แตกต่างออกไป อย่างไรก็ตามนี่ไม่ใช่กรณีของ PHP
cHao

13
@jie: คุณอาจต้องการใช้===แทน==เพราะ'0XAB' == '0xab'เป็นจริง
kennytm

17
กับการใช้งาน === แทน == เป็นสิ่งสำคัญเพราะการเปรียบเทียบสตริงเป็น 0 กับ == จะกลับจริงซึ่งเป็นเท็จอย่างเห็นได้ชัด ...
คาร์ลแอดเลอร์

4
@Kenny ยัง '0xAB' == '171'
พลวง

คำตอบ:


329

เหตุผลที่จะใช้มันเป็นเพราะ strcmp

ส่งกลับ <0 ถ้า str1 น้อยกว่า str2; > 0 ถ้า str1 มากกว่า str2 และ 0 ถ้าพวกเขาเท่ากัน

===ส่งกลับเฉพาะtrueหรือfalseมันไม่ได้บอกคุณซึ่งเป็นสตริง "มากกว่า"


9
ICIC สรรพสินค้าใหญ่ในกรณีที่ปัจจุบันของฉันฉันไม่จำเป็นต้องทราบว่าสตริงเป็นมากขึ้น :)
Jiew เม้ง

154
strcmp กับสตริงที่ตรงกันใช้เวลา 0.207852 วินาที strcmp กับสตริงที่ไม่ตรงกันใช้เวลา 0.215276 วินาที === กับสตริงที่ตรงกัน 0.067122 วินาที === กับสตริงที่ไม่ตรงกันใช้เวลา 0.057305 วินาที snipplr.com/view/758

3
การใช้งานอื่น ๆ สำหรับ strcmp จะแสดงการเรียงลำดับ เพื่อให้ชัดเจนเกี่ยวกับการเรียงลำดับ strcmp () ผลตอบแทน <0 ถ้า string1 เรียงลำดับก่อนที่ string2,> 0 ถ้า string2 เรียงลำดับก่อน string1 หรือ 0 ถ้าพวกเขาเหมือนกัน ตัวอย่างเช่น $ string_first = "aabo"; $ string_second = "aaao"; echo $ n = strcmp ($ string_first, $ string_second); จะกลับมามากกว่าศูนย์ขณะที่ aaao กำลังคัดแยกก่อน aabo
HTML Man

20
ทำไมคำตอบนี้จึงได้รับการโหวตมากที่สุด? ฉันกำลัง downvoting เพราะถึงแม้ว่ามันจะเป็นคำตอบที่คำถามนี้สมควรได้รับ แต่ไม่ใช่คำตอบที่ 'ถูกต้อง' คำตอบที่ถูกต้องควรเป็น 'ใช้ ===' เพราะมีคนจำนวนมากพูดไปแล้วในคำตอบอื่น ๆ
onur güngör

2
@onur güngörที่จริงแล้วสิ่งนี้จะตอบคำถามของ op ซึ่งก็คือSo is there any reason to use strcmp() ?ในขณะที่คำตอบของ Postfuturist ไม่ได้ โอ้นรก ... ไม่มีใครตอบดูเหมือนจะรวบรวมในครั้งเดียวใช้ของstrcmp()ที่ประสิทธิภาพการทำงานของ===และความน่าเชื่อถือที่ไม่ดีของ==สำหรับการเปรียบเทียบสตริง ... ดังนั้นฉันเพิ่มเหมืองในรายการ
Balmipour

222

คุณไม่ควรใช้==สำหรับการเปรียบเทียบสตริง ===ตกลง

$something = 0;
echo ('password123' == $something) ? 'true' : 'false';

เพียงเรียกใช้รหัสข้างต้นและคุณจะเห็นว่าทำไม

$something = 0;
echo ('password123' === $something) ? 'true' : 'false';

ตอนนี้มันดีขึ้นแล้ว


19
== ไม่เพียง แต่เป็นปัญหาสำหรับประเภทที่แตกต่างกัน บางครั้งจะให้ผลลัพธ์ที่ไม่คาดคิดแม้ว่าทั้งสองข้างจะเป็นสตริง ลอง '1e3' == '1,000'
พลวง

3
0 == 'password123' เป็นอย่างไร
Andy Lobel

24
@AndyLobel PHP บังคับให้ 'password123' เป็นตัวเลขโดยใช้กฎการเปรียบเทียบแบบหลวม ๆ เนื่องจากตัวถูกดำเนินการอื่นเป็นตัวเลขสตริงนั้นก็เหมือนกับ coerces ไปที่หมายเลข 0 และ PHP จะส่งกลับค่าจริงสำหรับการเปรียบเทียบ
postfuturist

8
var_dump ด่วน ((int) 'password123'); ช่วยให้ฉันเข้าใจว่าทำไมเรื่องนี้เกิดขึ้น ... ** ** อาย ... ผมชอบ === ประกอบการ
คาร์ลตัน

3
นี่เป็นเพราะใช้ '==' ถ้าหนึ่งในสองตัวถูกดำเนินการ castable เป็นจำนวน, php casts ทั้งตัวถูกดำเนินการไปยังหมายเลขและอื่น ๆ หากสตริงไม่หมายเลขถูกหล่อเป็นจำนวนมันใช้ค่าศูนย์ผลเท่ากับศูนย์ ดังนั้นผลลัพธ์ของการเปรียบเทียบกับ '==' แบบง่ายๆสามารถทำให้บางสิ่งไม่พึงประสงค์ได้
Luca C.

98

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

ตัวอย่างเช่น'1e3' == '1000'ผลตอบแทนจริง คุณควรใช้===แทน


16
แต่คุณสามารถ ===
โรมัน Newaza

11
@ Roman ใช่ แต่โปรแกรมเมอร์ PHP จำนวนมากไม่รู้ว่าต้องทำเช่นนั้น ดังนั้นการเตือน
พลวง

5
@Antimony ดังนั้นทำไมไม่บอกพวกเขาว่าพวกเขาควรทำอย่างไรในคำตอบของคุณ?
ทิม

43

ดี .. ตามรายงานข้อผิดพลาด phpนี้คุณยังสามารถรับ 0wned

<?php 
    $pass = isset($_GET['pass']) ? $_GET['pass'] : '';
    // Query /?pass[]= will authorize user
    //strcmp and strcasecmp both are prone to this hack
    if ( strcasecmp( $pass, '123456' ) == 0 ){
      echo 'You successfully logged in.';
    }
 ?>

มันให้คำเตือนคุณ แต่ยังคงข้ามการเปรียบเทียบ
คุณควรทำ===ตามที่ @postfuturist แนะนำ


5
ว้าว +1 อ้างจากลิงค์: "มันเป็นพฤติกรรมที่จัดตั้งขึ้นสำหรับฟังก์ชั่นที่ได้รับประเภทของอาร์กิวเมนต์ที่ไม่ถูกต้องเพื่อกลับมาเป็นโมฆะ" มันน่าอัศจรรย์เมื่อพิจารณาจากคู่มือบอกว่า: "คืนค่า <0 ถ้า str1 น้อยกว่า str2;> 0 ถ้า str1 มากกว่า str2 และ 0 ถ้าพวกมันเท่ากัน" Null ไม่ได้ถูกกล่าวถึงว่ามีความเป็นไปได้ แต่จะมีการกล่าวถึงในหน้าต่างๆเช่นหน้า man substr ถอนหายใจ
เจอร์รี่

แต่จะเกิดอะไรขึ้นเมื่อเมธอด form โพสต์ ...
3lokh

@NikhilGeorge มันฟังก์ชั่นในคำถามที่นี่คือ strcmp ไม่สำคัญว่าจะเปรียบเทียบกับอินพุตใด
Ajith

ในขณะที่รายงานข้อผิดพลาดบอกว่ามันเป็นเรื่องปกติที่จะกลับมาเป็นโมฆะ แต่มันไม่ถูกต้อง การเผยแพร่ PHP อย่างเป็นทางการทั้งหมดจาก PHP 4.3 ถึง PHP 7.3 จะไม่ส่งคืน null จากฟังก์ชันเหล่านี้ ฉันสงสัยว่าอาจเป็นรุ่นอัลฟ่าหรือเบต้าและไม่ว่าข้อบกพร่องที่ปิดอยู่จะไม่ถูกต้อง แต่ก็ถูกแก้ไขแล้ว ดู3v4l.org/Zq8tMสำหรับรายละเอียดซึ่งแสดงว่ามีผลกับ HHVM 3.11 - 3.19
Timo Tijhof

33

โปรดจำไว้เสมอว่าเมื่อเปรียบเทียบสตริงคุณควรใช้===โอเปอเรเตอร์ (การเปรียบเทียบที่เข้มงวด) และไม่ใช่ ==โอเปอเรเตอร์ (การเปรียบเทียบที่หลวม)


8
อันที่จริงผมคิดว่ามันปลอดภัยที่จะบอกว่าคุณควรใช้===เมื่อเปรียบเทียบกับอะไร
rink.attendant.6

22

สรุปคำตอบทั้งหมด:

  • ==เป็นความคิดที่ดีสำหรับการเปรียบเทียบสตริง
    มันจะให้ผลลัพธ์ที่ "น่าประหลาดใจ" ในหลาย ๆ กรณี อย่าไว้ใจมัน

  • === ไม่เป็นไรและจะให้ประสิทธิภาพที่ดีที่สุดแก่คุณ

  • strcmp() ควรใช้หากคุณต้องการพิจารณาว่าสตริงใดที่ "ดีกว่า" ซึ่งโดยปกติจะใช้สำหรับการเรียงลำดับการดำเนินการ


20

การใช้==อาจเป็นอันตราย

โปรดทราบว่ามันจะส่งตัวแปรไปยังประเภทข้อมูลอื่นหากทั้งสองแตกต่างกัน

ตัวอย่าง:

  • echo (1 == '1') ? 'true' : 'false';
  • echo (1 == true) ? 'true' : 'false';

อย่างที่คุณเห็นสองสิ่งนี้มาจากประเภทที่แตกต่างกัน แต่ผลลัพธ์คือtrueซึ่งอาจไม่เป็นสิ่งที่รหัสของคุณคาดหวัง

ใช้===แต่แนะนำเป็นแสดงให้เห็นว่าการทดสอบว่ามันเป็นบิตเร็วกว่าและทางเลือกกรณีตายของมันstrcmp()strcasecmp()

googling อย่างรวดเร็วตะโกนการเปรียบเทียบความเร็วนี้: http://snipplr.com/view/758/


1
บางครั้งมันก็ใช้มันแตกต่างกันแม้ว่ามันจะมีชนิดเดียวกันก็ตาม
พลวง

แม้เมื่อเปรียบเทียบสองสายที่เป็นตัวแทนจำนวนเต็มเช่น"012" == "12"PHP การเปลี่ยนแปลงประเภทของทั้งสองสายเป็นจำนวนเต็มและส่งกลับมาแล้ว12 == 12 true
GoTo


6

strcmp จะส่งคืนค่าที่แตกต่างกันตามสภาพแวดล้อมที่ใช้ (Linux / Windows)!

เหตุผลก็คือมันมีข้อบกพร่องตามที่รายงานข้อผิดพลาดบอกว่า https://bugs.php.net/bug.php?id=53999

กรุณาจัดการด้วยความระมัดระวัง !! ขอบคุณ


มันจะส่งคืนค่า 0 เสมอหากสตริงมีค่าเท่ากัน +1 สำหรับการระมัดระวังเกี่ยวกับการดูแลเกี่ยวกับค่าอื่น ๆ กว่า 0 แม้ว่า
ศ. Falken ผิดสัญญาเมื่อ

4

คุณสามารถใช้strcmp()ถ้าคุณต้องการที่จะสั่งซื้อ / เปรียบเทียบสตริงlexicographically หากคุณเพียงแค่ต้องการตรวจสอบความเท่าเทียมกันก็==เป็นเรื่องปกติ


1
เช่นเดียวกับในusort ในความเป็นจริงมันค่อนข้างทำสำหรับการเรียงลำดับ
ชาร์ลส์

@ Charles ขอบคุณ Wikipedia ทำให้ดวงตาของฉันจ้องมอง
cbednarski

1
เพื่อให้ชัดเจนเกี่ยวกับการเรียงลำดับ strcmp () ผลตอบแทน <0 ถ้า string1 เรียงลำดับก่อนที่ string2,> 0 ถ้า string2 เรียงลำดับก่อน string1 หรือ 0 ถ้าพวกเขาเหมือนกัน ตัวอย่างเช่น $ string_first = "aabo"; $ string_second = "aaao"; echo $ n = strcmp ($ string_first, $ string_second); จะกลับมามากกว่าศูนย์ขณะที่ aaao กำลังคัดแยกก่อน aabo
HTML Man

@postfuturist ===ฉันแน่ใจว่ามันพิมพ์ผิดและพวกเขาหมายถึง
เถ้าถ่าน

4

ฟังก์ชั่นสามารถช่วยในการเรียงลำดับ เพื่อให้ชัดเจนเกี่ยวกับการเรียงลำดับ strcmp () ผลตอบแทนน้อยกว่า 0 ถ้า string1 เรียงลำดับก่อนที่ string2 มากกว่า 0 ถ้า string2 เรียงลำดับก่อน string1 หรือ 0 ถ้าพวกเขาเหมือนกัน ตัวอย่างเช่น

$first_string = "aabo";
$second_string = "aaao";
echo $n = strcmp($first_string,$second_string);

ฟังก์ชั่นจะกลับมามากกว่าศูนย์เนื่องจาก aaao กำลังคัดแยกก่อน aabo


0

PHP แทนที่จะใช้การเรียงลำดับตัวอักษรให้ใช้ค่าASCIIของอักขระเพื่อทำการเปรียบเทียบ อักษรตัวพิมพ์เล็กมีค่าASCIIสูงกว่าเมืองหลวง จะดีกว่าถ้าใช้ตัวดำเนินการเอกลักษณ์===เพื่อทำการเปรียบเทียบแบบนี้ strcmp ()เป็นฟังก์ชั่นเพื่อทำการเปรียบเทียบสตริงที่ปลอดภัยของไบนารี ใช้สองสตริงเป็นอาร์กิวเมนต์และส่งกลับ <0 ถ้า str1 น้อยกว่า str2 > 0 ถ้า str1 มากกว่า str2 และ 0 ถ้าพวกเขาเท่ากัน นอกจากนี้ยังมีcase-insensitive version ชื่อstrcasecmp ()ที่แปลงสตริงเป็นตัวพิมพ์เล็กก่อนแล้วจึงทำการเปรียบเทียบ


0

if ($password === $password2) { ... }ไม่ใช่สิ่งที่ปลอดภัยที่ต้องทำเมื่อเปรียบเทียบรหัสผ่านหรือแฮชรหัสผ่านที่หนึ่งในอินพุตนั้นถูกควบคุมโดยผู้ใช้
ในกรณีดังกล่าวจะสร้าง oracle กำหนดเวลาเพื่อให้ผู้โจมตีได้รับการแฮชรหัสผ่านจริงจากความแตกต่างของเวลาดำเนินการ
ใช้if (hash_equals($password, $password2)) { ... }แทนเนื่องจากhash_equalsดำเนินการ "การเปรียบเทียบการโจมตีด้วยสตริงที่ปลอดภัยเวลา"

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