1. Einleitung
PHP stellt die Funktionen is_numeric() und ctype_digit() bereit, um einen String darauf zu prüfen, ob er ein gültiger Integer wäre. Beide Funktionen sind aber nicht perfekt, so gibt is_numeric() nicht nur für gültige Integer, sondern auch für gültige Floats true zurück. ctype_digit() wiederum akzeptiert keine Plus- und Minuszeichen am Anfang des Strings, sodass etwa die Anwendung der Funktion auf negative Zahlen (als Strings) false ergibt. Genauso sind auch keine Leerzeichen am Anfang oder Ende möglich. Daher werden nachfolgend nicht nur is_numeric() und ctype_digit(), sondern auch drei eigene Implementierungen vorgestellt.
2. is_numeric
Die Funktion is_numeric($number) prüft, ob der übergebene String ein gültiger Integer- oder Float-Wert wäre. Im Beispiel wird sie auf verschiedene mögliche Strings angewendet.
<?php $vars = array('asd', '15a', '', '15', '1.3', '1,3', '0', ' 23', '-10', '+10', '03', '999999999999', '0xFF', '12e3'); foreach ($vars as $var) { echo $var.": "; if (is_numeric($var)) { echo "true\n"; } else { echo "false\n"; } } ?>
asd: false 15a: false : false 15: true 1.3: true 1,3: false 0: true 23: true -10: true +10: true 03: true 999999999999: true 0xFF: true 12e3: true
Wie den Ergebnissen entnommen werden kann, arbeitet die Funktion sehr zuverlässig. Im Gegensatz zum ursprünglichen Ziel akzeptiert sie aber auch alle Float-Werte.
3. ctype_digit
ctype_digit() wird auf einen String angewendet und gibt true zurück, wenn dieser ein oder mehr Ziffern zwischen 0 und 9 enthält — und kein einziges anderes Zeichen. Das ist nützlich, wenn der übergebene Integer immer nur auf diesen Ziffern besteht. Sobald er aber auch zum Beispiel Leerzeichen oder ein Minuszeichen enthalten kann ist das Ergebnis von ctype_digit() nicht mehr korrekt.
<?php $vars = array('asd', '15a', '', '15', '1.3', '1,3', '0', ' 23', '-10', '+10', '03', '999999999999', '0xFF', '12e3'); foreach ($vars as $var) { echo $var.": "; if (ctype_digit($var)) { echo "true\n"; } else { echo "false\n"; } } ?>
asd: false 15a: false : false 15: true 1.3: false 1,3: false 0: true 23: false -10: false +10: false 03: true 999999999999: true 0xFF: false 12e3: false
4. Angepasstes ctype_digit
Wie bereits erläutert, scheitert ctype_digit() bei allen Strings, die am Anfang oder Ende Leerzeichen oder Tabs haben, sowie auch bei allen, die mit einem Pluszeichen oder Minuszeichen beginnen. Diese Schwachstellen werden nachfolgend in einer eigenen Funktion behoben. Als Name für die Funktion wird „ctype_digit_sign” verwendet. Sie erwartet — wie ctype_digit() — einen String als Parameter. Auf diesen wird zunächst ein Mal trim() angewendet, um alle Leerzeichen, Tabs und Zeilenumbrüche am Anfang und Ende des Strings zu entfernen. Anschließend wird geprüft, ob der String aus mehr als einem Zeichen besteht. Falls nicht wird ctype_digit() auf das eine Zeichen angewendet und das Ergebnis zurückgegeben (da der String dann nur eine Zahl enthalten darf). Falls er aus mehr als einem Zeichen besteht, ist ein Plus oder Minus am Anfang erlaubt. Daher wird ermittelt, ob das erste Zeichen eine Zahl oder ein Plus/Minus ist und ob alle Zeichen nach der ersten Stelle nach ctype_digit() nur Zahlen sind.
<?php function ctype_digit_sign($var) { if (!is_string($var) || !isset($var[0])) { return false; } else { $var = trim($var); if (!isset($var[1])) { return ctype_digit($var); } else { return ($var[0]==='-' || $var[0]==='+' || ctype_digit($var[0])) && ctype_digit(substr($var, 1)); } } } $vars = array('asd', '15a', '', '15', '1.3', '1,3', '0', ' 23', '-10', '+10', '03', '999999999999', '0xFF', '12e3'); foreach ($vars as $var) { echo $var.": "; if (ctype_digit_sign($var)) { echo "true\n"; } else { echo "false\n"; } } ?>
asd: false 15a: false : false 15: true 1.3: false 1,3: false 0: true 23: true -10: true +10: true 03: true 999999999999: true 0xFF: false 12e3: false
5. preg_match
Den selben Effekt wie in der angepassten Version von ctype_digit kann man auch über einen regulären Ausdruck erreichen. Das Prüfen des Strings auf einen regulären Ausdruck erfolgt mittels preg_match('/regex/', $zuPruefendeVariable). Auch hier werden mit trim() Leerzeichen, Tabs und Zeilenumbrüche am Anfang und Ende entfernt. Über den Abschnitt ^(\-|\+)? aus dem regulären Ausdruck wird bestimmt, dass der String optional mit einem Plus- oder Minuszeichen beginnen darf. Über [0-9]+$ wiederum wird festgelegt, dass anschließend ein bis beliebig viele Zahlen (und sonst nichts) folgen dürfen.
<?php function preg_match_int($var) { return is_string($var) && preg_match('/^(\-|\+)?[0-9]+$/', trim($var)); } $vars = array('asd', '15a', '', '15', '1.3', '1,3', '0', ' 23', '-10', '+10', '03', '999999999999', '0xFF', '12e3'); foreach ($vars as $var) { echo $var.": "; if (preg_match_int($var)) { echo "true\n"; } else { echo "false\n"; } } ?>
asd: false 15a: false : false 15: true 1.3: false 1,3: false 0: true 23: true -10: true +10: true 03: true 999999999999: true 0xFF: false 12e3: false
6. Konvertierung zu Integer und zurück
Eine weitere mögliche Methode ist das „testweise” Konvertieren zu Integer. Im nachfolgenden Beispiel wird eine Funktion definiert, die den übergebenen String in einen Integer umwandelt und anschließend wieder zurück in einen String. Wenn der String am Ende dem String vom Anfang gleicht, dann ist der String vom Anfang ein gültiger Integer, sonst nicht. Die Funktion ist weniger genau als der reguläre Ausdruck, da beim Konvertieren zu Integer hin z. B. das führende Pluszeichen für positive Zahlen verloren geht.
<?php function may_be_int($var) { return is_string($var) && strval(intval($var))===$var; } $vars = array('asd', '15a', '', '15', '1.3', '1,3', '0', ' 23', '-10', '+10', '03', '999999999999', '0xFF', '12e3'); foreach ($vars as $var) { echo $var.": "; if (may_be_int($var)) { echo "true\n"; } else { echo "false\n"; } } ?>
asd: false 15a: false : false 15: true 1.3: false 1,3: false 0: true 23: false -10: true +10: false 03: false 999999999999: false 0xFF: false 12e3: false