Porównanie ciągów za pomocą „==” vs. „strcmp ()”


334

Wygląda na to, że ===operator PHP rozróżnia małe i wielkie litery. Czy istnieje więc powód do korzystania strcmp()?

Czy można bezpiecznie wykonać następujące czynności?

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

10
Co ma związek z rozróżnianiem wielkości liter strcmp?
kennytm

1
@KennyTM: strcmprozróżnia małe i wielkie litery. W niektórych językach, takich jak VB, porównywanie ciągów może nie być, a zatem zwraca inny wynik. Jednak nie dotyczy to PHP.
cHao

13
@jie: Możesz użyć ===zamiast, ==ponieważ '0XAB' == '0xab'jest to prawda.
kennytm

17
użycie === zamiast == jest ważne, ponieważ porównanie dowolnego łańcucha do 0 z == zwróci true, co oczywiście jest fałszem ...
Karl Adler

4
@ Kenny Również „0xAB” == „171”
Antymon

Odpowiedzi:


329

Powodem tego jest to, że strcmp

zwraca <0, jeśli str1 jest mniejsze niż str2; > 0, jeśli str1 jest większy niż str2, i 0, jeśli są równe.

===zwraca tylko truelub falsenie mówi, który jest ciągiem „większym”.


9
icic tho w mojej obecnej sprawie, nie muszę wiedzieć, który ciąg jest większy :)
Jiew Meng

154
strcmp z pasującymi ciągami zajął 0,207852 sekundy strcmp z niepasującymi ciągami zajął 0,215276 sekund === z pasującymi ciągami zajął 0,067122 sekundy === z niepasującymi ciągami zajął 0,057305 sekund snipplr.com/view/758

3
Inne użycie strcmp pokazuje sortowanie. Aby wyjaśnić sortowanie. strcmp () zwraca <0, jeśli ciąg1 sortuje przed ciągiem 2,> 0, jeśli ciąg 2 sortuje przed ciągiem 1 lub 0, jeśli są takie same. Na przykład $ string_first = "aabo"; $ string_second = "aaao"; echo $ n = strcmp ($ string_first, $ string_second); zwróci więcej niż zero, ponieważ aaao sortuje przed aabo.
HTML Man,

20
Dlaczego ta odpowiedź ma najwięcej pozytywnych opinii? Oddaję głos, ponieważ chociaż jest to odpowiedź, na którą to pytanie zasługuje, ale nie „właściwa” odpowiedź. Prawidłowa odpowiedź powinna brzmieć „Użyj ===”, ponieważ wiele osób już powiedziało w innych odpowiedziach.
onur güngör

2
@onur Güngör Właściwie to robi odpowiedzi Pytanie PO, która jest So is there any reason to use strcmp() ?, a odpowiedź Postfuturist nie robi. Och, do diabła ... nikt odpowiedź wydawała się skompilować na raz do użytku z strcmp(), na wydajność z ===, a złe niezawodności z ==porównań łańcuchowych ... więc dodałem kopalnię do listy.
Balmipour

222

Nigdy nie należy używać ==do porównywania ciągów. ===jest OK

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

Po prostu uruchom powyższy kod, a zobaczysz dlaczego.

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

Teraz jest trochę lepiej.


19
== to nie tylko problem dla różnych typów. Czasami daje nieoczekiwane rezultaty, nawet jeśli obie strony są ciągiem. Spróbuj „1e3” == „1000”
Antymon

3
w jaki sposób 0 == „hasło123”?
Andy Lobel,

24
@AndyLobel PHP wymusza „hasło123” na liczbę, używając dziwnych luźnych reguł porównywania, ponieważ drugi operand jest liczbą, ten ciąg, jak większość, wymusza na cyfrę 0, a PHP zwraca wartość true dla porównania.
postfuturist

8
Szybki var_dump ((int) 'password123'); pomógł mi w pełni zrozumieć, dlaczego tak się stało ... ** zawstydzony ** ... Naprawdę podoba mi się operator ===
Carlton,

3
jest tak, ponieważ użycie „==”, jeśli jeden z dwóch operandów można rzutować na liczby, php rzutuje oba operandy na liczby, a ponadto, jeśli ciąg nie będący liczbą jest rzutowany na liczbę, przyjmuje wartość zero, co daje wartość równą zero, więc wynik porównania z prostym „==” może coś niechcianego
Luca C.

98

Nie używaj ==w PHP. Nie zrobi tego, czego oczekujesz. Nawet jeśli porównujesz ciągi z ciągami, PHP domyślnie rzuci je na zmiennoprzecinkowe i wykona porównanie numeryczne, jeśli są wyświetlane liczbowo.

Na przykład '1e3' == '1000'zwraca true. Zamiast tego powinieneś użyć ===.


16
Ale możesz po prostu ===.
Roman Newaza,

11
@Roman tak, ale wielu programistów PHP nie wie, że muszą to zrobić. Stąd ostrzeżenie.
Antimony,

5
@Antimony Więc dlaczego nie powiedz im, co powinni zrobić w odpowiedzi?
Tim

43

Cóż ... zgodnie z tym raportem błędu php , możesz nawet uzyskać 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.';
    }
 ?>

Daje ostrzeżenie, ale nadal pomija porównanie.
Powinieneś postępować ===zgodnie z sugestią @postfuturist.


5
Wow +1. Cytat z linku: „Ustanowiono zachowanie funkcji, które otrzymują niewłaściwy typ argumentów, aby zwracały wartość null”. To niesamowite, biorąc pod uwagę, że instrukcja mówi tylko: „Zwraca <0, jeśli str1 jest mniejsze niż str2;> 0, jeśli str1 jest większe niż str2, a 0, jeśli są równe”. Null nie jest wymieniony jako możliwość, ale na stronach takich jak podstrona man jest on wymieniony. westchnienie
Gerry

Ale czy to samo dzieje się, gdy metoda formularza jest wysyłana ...?
3lokh

@NikhilGeorge Tak, chodzi tutaj o funkcję strcmp. Nie ma znaczenia, z którymi danymi wejściowymi są porównywane.
Ajith,

Chociaż raport o błędzie mówi, że w porządku było zwrócenie wartości null, jest to niepoprawne. Wszystkie oficjalne wersje PHP od PHP 4.3 do PHP 7.3 nie zwracają wartości null dla tych funkcji. Podejrzewam, że mogła to być wersja alfa lub beta i niezależnie od tego, że błąd, który został zamknięty, jest nieprawidłowy, został naprawiony. Zobacz 3v4l.org/Zq8tM, aby uzyskać szczegółowe informacje, które pokazują, że ma on wpływ na HHVM 3.11 - 3.19.
Timo Tijhof

33

Zawsze pamiętaj, że porównując łańcuchy, powinieneś używać ===operatora (ścisłe porównanie), a nie == operatora (luźne porównanie).


8
Właściwie uważam, że bezpiecznie jest powiedzieć, że powinieneś używać, ===gdy porównujesz cokolwiek .
rink.attendant. 6

22

Podsumowując wszystkie odpowiedzi:

  • ==to zły pomysł na porównania ciągów.
    W wielu przypadkach daje „zaskakujące” wyniki. Nie ufaj temu.

  • === jest w porządku i da ci najlepszą wydajność.

  • strcmp() należy użyć, jeśli chcesz ustalić, który ciąg znaków jest „większy”, zwykle do operacji sortowania.


20

Używanie ==może być niebezpieczne.

Zauważ, że rzutowałoby zmienną na inny typ danych, jeśli oba się różnią.

Przykłady:

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

Jak widać, te dwa są z różnych typów, ale wynik jest taki true, że może nie być to, czego oczekuje Twój kod.

Stosując ===jednak jest zalecana jako pokazach testowych, że jest to nieco szybciej niż strcmp()a jego wielkość liter alternatywny strcasecmp().

Szybkie googling krzyczy to porównanie prędkości: http://snipplr.com/view/758/


1
Czasami rzuca je na inny typ, nawet jeśli mają już ten sam typ.
Antymon

nawet porównując dwa łańcuchy reprezentujące liczbę całkowitą taką jak "012" == "12"php, zmienił typ obu łańcuchów na liczbę całkowitą, 12 == 12a następnie zwrócił true.
GoTo



4

Możesz użyć, strcmp()jeśli chcesz zamówić / porównać ciągi leksykograficzne . Jeśli chcesz po prostu sprawdzić równość, ==jest w porządku.


1
Jak w usort . W rzeczywistości jest on przeznaczony do sortowania.
Charles

@Charles Thanks. Wikipedia sprawiła, że ​​moje oczy płonęły.
cbednarski

1
Aby wyjaśnić sortowanie. strcmp () zwraca <0, jeśli ciąg1 sortuje przed ciągiem 2,> 0, jeśli ciąg 2 sortuje przed ciągiem 1 lub 0, jeśli są takie same. Na przykład $ string_first = "aabo"; $ string_second = "aaao"; echo $ n = strcmp ($ string_first, $ string_second); zwróci więcej niż zero, ponieważ aaao sortuje przed aabo.
HTML Man

@postfuturist Jestem pewien, że to literówka i mieli na myśli ===.
popiół

4

Również funkcja może pomóc w sortowaniu. Aby wyjaśnić sortowanie. strcmp () zwraca mniej niż 0, jeśli string1 sortuje przed string2, większy niż 0, jeśli string2 sortuje przed string1 lub 0, jeśli są takie same. Na przykład

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

Funkcja zwróci wartość większą niż zero, ponieważ aaao sortuje przed aabo.


0

PHP Zamiast korzystać z sortowania alfabetycznego, użyj wartości ASCII znaku, aby dokonać porównania. Małe litery mają wyższą wartość ASCII niż wielkie litery . Lepiej jest użyć operatora tożsamości ===, aby dokonać tego rodzaju porównania. strcmp () to funkcja służąca do porównywania bezpiecznych ciągów binarnych. Jako argument przyjmuje dwa łańcuchy i zwraca <0, jeśli str1 jest mniejszy niż str2; > 0, jeśli str1 jest większy niż str2, i 0, jeśli są równe. Istnieje również wersja bez rozróżniania wielkości liter o nazwie strcasecmp (), która najpierw konwertuje ciągi na małe, a następnie porównuje je.


0

if ($password === $password2) { ... }nie jest bezpieczną rzeczą przy porównywaniu haseł i skrótów haseł, gdy jedno z wejść jest kontrolowane przez użytkownika.
W takim przypadku tworzy wyrocznię czasową, która pozwala osobie atakującej na uzyskanie rzeczywistego skrótu hasła na podstawie różnic w czasie wykonywania.
Użyj if (hash_equals($password, $password2)) { ... }zamiast tego, ponieważ hash_equals wykonuje „porównanie bezpiecznego ciągu łańcucha w czasie”.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.