• Jetzt anmelden. Es dauert nur 2 Minuten und ist kostenlos!

Problem mit strpos() bzw. stripos()

bodo92

Aktives Mitglied
Guten Abend,

könnt ihr mit bitte bei einem kleinen Problem helfen.

Ich habe eine Browserunterscheidung mittels PHP geschrieben.


Also ich Frage "$_SERVER['HTTP_USER_AGENT']" ab und Schnipsel mir den gelieferten Browser mittels strpos() bzw. stripos() aus. War mir nicht sicher welcher. Jetz aber das Problem.

Meine Abfrage:
PHP:
if (stripos($_SERVER['HTTP_USER_AGENT'], "Opera")) {
$browser = "Opera";
$styledata = "v_1_03.css";
}
oder:
PHP:
if (strpos($_SERVER['HTTP_USER_AGENT'], "Opera")) {
$browser = "Opera";
$styledata = "v_1_03.css";
}

Jezt läd er mir aber immer die Datei für Unbekannt:
PHP:
if (!isset($browser)) {
$browser = "[Unbekannt]";
$styledata = "v_1_03_nd.css";
}

Meine über echo ausgegebenen Daten: ( $_SERVER['HTTP_USER_AGENT'], $browser )
HTML:
<!-- User Agent: Opera/9.80 (Windows NT 6.1; U; de) Presto/2.9.168 Version/11.51 -->
<!-- Sie benutzen folgenden Browser: [Unbekannt] -->
<link rel="stylesheet" type="text/css" href="../include/css/v_1_03_nd.css">

freundliche Grüße

bOdO ;)
 
strpos und stripos geben die Position zurück, an der der gesuchte String beginnt. Da „Opera“ ganz zu Beginn steht, geben beide Befehle Offset 0 zurück. In der if-Bedingung ist 0 dann gleichbedeutend mit false. Prüfe auf strpos(…) !== false.

Wenn ein Begriff tatsächlich nicht gefunden wird, geben strpos und stripos false zurück.
 
kann ich das einfach mit:

PHP:
if (!stripos($_SERVER['HTTP_USER_AGENT'], "Opera")) {
$browser = "Opera";
$styledata = "v_1_03.css";
}

machen oder muss ich den umständlichen Wert wählen?:
PHP:
<?php
$meinString = 'abc';
$findMich   = 'a';
$pos = strpos($meinString, $findMich);

// Der !==-Operator kann ebenfalls verwendet werden. Die Verwendung von != von
// != würde in unserem Beispiel nicht wie erwartet arbeiten, da die Position
// von 'a' 0 ist. Das Statement (0 != false) evaluiert hierbei zu false.
if ($pos !== false) {
    echo "Der String '$findMich' wurde im String '$meinString' gefunden";
    echo " und befindet sich an Position $pos";
} else {
    echo "Der String '$findMich' wurde nicht im String '$meinString' gefunden";
}
?>
Quelle:PHP: strpos - Manual
 
Also, strpos (stripos auch) gibt entweder die Fundstelle als Integer zurück oder den Wert false als Boolean.

PHP:
<?php

//           Offset
//           ---------
//           012345678
$haystack = 'holztisch';

var_dump(strpos($haystack, 'holz'));  // int(0)
var_dump(strpos($haystack, 'tisch')); // int(4)
var_dump(strpos($haystack, 'stuhl')); // bool(false)

Immer dann, wenn ein Integer (auch int(0)) zurückgegeben wird, heißt das: Der gesuchte String wurde gefunden.

Nun besteht aber das „Problem“, dass eine if-Bedingung einen Ausdruck immer boolsch (true oder false) auswertet, die Zahl 0 aber zu false konvertiert wird.

PHP:
var_dump((bool) 0);     // bool(false)
var_dump((bool) 4);     // bool(true)
var_dump((bool) false); // bool(false)

Anders gesagt: Der Code if (strpos($haystack, 'needle')) { … } unterscheidet nicht zwischen der Funktionsrückgabe 0 (= am Stringanfang gefunden) und false (= nicht gefunden).

Da aber int(0) ein „gefunden“ anzeigt, musst du die Prüfung der Funktionsrückgabe als if (strpos($haystack, 'needle') !== false) { … } schreiben.

Das bedeutet: „Wenn der Rückgabewert von strpos nicht bool(false) ist, dann…”

Auch klappen würde vermutlich: if (is_int(strpos($haystack, 'needle')) { … } („Wenn strpos einen Wert vom Typ Integer zurückliefert, dann…“)

Schöner wäre es eventuell, wenn strpos für „nicht gefunden“ ein -1 zurückliefern würde. Aber dem ist eben nicht so. ;)

Die Bedingung…

PHP:
!stripos($_SERVER['HTTP_USER_AGENT'], "Opera")

…bedeutet: „Wenn Opera im String an Stelle 0 steht oder nicht enthalten ist, dann…“

!(0) wird zu true und !(false) wird zu true. !(1) usw. wird alles zu false, da Zahlen größer 0 als true ausgewertet werden.
 
Vielen Vielen Dank, für die schnelle und gut Verständliche Antwort :)

Funktioniert super.



freundliche Grüße

bOdO
 
Hättest es auch einfach lösen können, wenn du den durchsuchten String am Anfang verlängerst, so dass kein 0 zurück gegeben werden kann, etwa so:
stripos('#' . $_SERVER['HTTP_USER_AGENT'], "Opera")
Dann wäre entweder false oder was >=1 erschienen und das Problem mit der Doppelbedeutung von 0 ist vom Tisch :-).
 
oder mit
PHP:
 if (stristr($_SERVER['HTTP_USER_AGENT'], "Opera")) {
$browser = "Opera";
 
NetAktiv schrieb:
Hättest es auch einfach lösen können, wenn du den durchsuchten String am Anfang verlängerst, so dass kein 0 zurück gegeben werden kann, etwa so:
stripos('#' . $_SERVER['HTTP_USER_AGENT'], "Opera")

Das ist für mich an dieser Stelle ein Hack (auf einer Ebene mit „Typecasting“ per $s = "$n";), womit ich aber nicht sagen will, dass man sowas generell nicht machen könnte. Mit !== false und (string) existieren aber für diese Anwendungen gute Lösungen.

Jedenfalls sollte ein Programmierer wissen, welche Rückgabewerte die eingesetzten Funktionen liefern und er sollte auch wissen, was die „dreistelligen“ Vergleichsoperatoren in PHP besagen.

- PHP: PHP type comparison tables - Manual

PHP ist zwar untypisiert, nutzt aber manchmal typisierte Rückgabewerte. (Fehlende Typisierung ist sicherlich einfach nicht konsequent durchzusetzen.)



Bedingungen mit implizitem Typecasting finde ich aber ohnehin hässlich, da sie oftmals wenig „sprechend“ sind.

PHP:
$x = 10;

while ($x) {
    echo $x, "\n";
    $x--;
}



$elements = array('eins', 'zwei', 'drei');

while ($elements) {
    echo array_shift($elements), "\n";
}

Wie soll man denn das verstehen? Solange $x „wahr“ ist, … $x ist doch 'ne Zahl… Wie soll eine Zahl „wahr“ sein? Wieso wird sie „unwahrer“, wenn sie dekrementiert wird?

Und ein Array ist „wahr“, wenn es Elemente enthält, ansonsten „falsch“? Leuchtet ein wie eine kaputte Straßenlaterne.



Kann man aber alles machen. Tun wir auch ständig.

Bei etwa preg_match müsste im Grunde auf === 1 geprüft werden, denn die Funktion liefert 1 oder 0, nicht true oder false.

Das heißt…

preg_match() returns the number of times pattern matches. That will be either 0 times (no match) or 1 time because preg_match() will stop searching after the first match. preg_match_all() on the contrary will continue until it reaches the end of subject. preg_match() returns FALSE if an error occurred.

Sie liefert im Fehlerfall auch noch false, was uns hier wirklich drei mögliche Rückgaben gibt: 1=gefunden, 0=nicht gefunden, false=Fehler.

Auch beim beliebten while ($row = mysql_fetch_assoc(…)) { … } sieht es wenig anders aus. Was wir da eigentlich sagen wollen, ist: while (($row = mysql_fetch_assoc(…)) !== null) { … }.


Oder bei sysops Variante:

Die stristr-Funktion gibt im Erfolgsfall den Suchstring zurück. „Opera“ in diesem Fall. if ("Opera") ist wahr – na klar, wieso auch nicht.

Blöd wird es nur, wenn statt "Opera" nach "0" (Null) gesucht wird. Der String "0" ist nämlich false.

Abhilfe in diesem zugegebenermaßen wohl nicht sonderlich wahrscheinlichen Fall schafft auch hier stristr($_SERVER['HTTP_USER_AGENT'], "Opera") !== false.
 
Zurück
Oben