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) { ... }
Jiew Meng
źródło
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”.

deceze
źródło
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.

postfuturist
źródło
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ć ===.

Antymon
źródło
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.

Ajith
źródło
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).

DataPriest
źródło
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.

Balmipour
źródło
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/

Nikola Petkanski
źródło
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
12

strcmp()i w ===obu rozróżniana jest wielkość liter, ale ===jest znacznie szybszy

przykładowy kod: http://snipplr.com/view/758/

ungalcrys
źródło
6

strcmp zwróci różne wartości w zależności od środowiska, w którym działa (Linux / Windows)!

Powodem jest to, że ma błąd, ponieważ raport o błędzie mówi https://bugs.php.net/bug.php?id=53999

Proszę postępować ostrożnie !! Dziękuję.

kta
źródło
Jednak zawsze zwraca 0, jeśli ciągi znaków są równe. +1 za ostrożność przy dbaniu o jakąkolwiek wartość inną niż 0.
Umowa prof. Falkena została naruszona
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.

Daniel Egeberg
źródło
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.

HTML Man
źródło
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.

Alireza Rahmani Khalili
źródło
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”.

Ali
źródło