PHP: Test if string contains only numbers, dashes, parentheses and spaces

skij
skij used Ask the Experts™
on
Using PHP, how cant I test if string contains only numbers, dashes, parentheses and spaces? If it contains anything else, like a letter, it should return false.
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Fixer of Problems
Most Valuable Expert 2014
Commented:
'preg_match' is probably what you want.  The difficulty is constructing the matching instruction for what you want.

http://php.net/manual/en/function.preg-match.php

This seems to work.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
 "http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
<title>Preg_match</title>
</head>
<body>

<?php
$str1 = "This is all alpha.";
$str2 = "1234567890-() ";
// The "i" after the pattern delimiter indicates a case-insensitive search
if (preg_match("/[^0-9-() ]/", $str2)) {
    echo "A match was found.";
} else {
    echo "A match was not found.";
}
?>

</body>
</html>

Open in new window

Most Valuable Expert 2011
Top Expert 2016

Commented:
Here is a way to annotate the solution with comments and show how to test it.
http://iconoun.com/demo/temp_skij.php
<?php // demo/temp_skij.php

/**
 * http://www.experts-exchange.com/questions/28719388/PHP-Test-if-string-contains-only-numbers-dashes-parentheses-and-spaces.html
 *
 * http://php.net/manual/en/function.preg-match.php
 */
error_reporting(E_ALL);
echo '<pre>';

// A FILTER FUNCTION
function skij_filter($str)
{
    // A REGEX FOR THE EXPECTED FILTERS
    $rgx
    = '/'     // REGEX DELIMITER
    . '['     // START OF CHARACTER CLASS
    . '^'     // NEGATION - MATCH NONE OF THESE
    . '0-9'   // RANGE OF NUMBERS
    . '-'     // THE DASH
    . '()'    // THE PARENTHESES
    . ' '     // THE BLANK
    . ']'     // ENDOF CHARACTER CLASS
    . '/'     // REGEX DELIMITER
    ;
    // TEST FOR A NEGATIVE OF A NEGATIVE CONDITION (!)
    if (!preg_match($rgx, $str)) return TRUE;
    return FALSE;
}

// MAYBE A TELEPHONE NUMBER?  SOME TEST CASES
$tests =
[ '123'
, '(301) 555-1212'
, 'crump'
, '11111111111111111111111111111111111111111111111111111'
, '999-999-9999'
, '((((((((((((((()'
, '--------------'
, '-99993'
, '1-800-BIG-DOGS'
]
;

// RUN THE TESTS AND SHOW THE RESULTS
foreach ($tests as $str)
{
    echo PHP_EOL;
    if ( skij_filter($str) )
    {
        echo ' OK: ';
    }
    else
    {
        echo 'NOK: ';
    }
    echo $str;
}

Open in new window

Most Valuable Expert 2011
Top Expert 2016

Commented:
On the chance that you're looking for phone number authentication, there is a well-understood design pattern ;-)
<?php // demo/validate_phone_numbers.php

/**
 * A function to validate a USA phone number and return a normalized string
 *
 * MAN PAGE: http://discuss.fogcreek.com/joelonsoftware3/default.asp?cmd=show&ixPost=102667&ixReplies=15
 * MAN PAGE: http://www.nanpa.com/number_resource_info/index.html
 */
error_reporting(E_ALL);


function strtophone($phone, $format=FALSE, $letters=FALSE, $dlm='-')
{
    if ($letters)
    {
        // TURN INPUT LIKE 1-800-BIG-DOGS
        // INTO INPUT LIKE 1-800-244-3647
        $phone = strtoupper($phone);
        if (preg_match('/[A-Z]/', $phone))
        {
            $phone = strtr
            ( $phone
            , 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
            , '22233344455566677778889999'
            )
            ;
        }
    }

    // DISCARD NON-NUMERIC CHARACTERS
    $phone = preg_replace('/[^0-9]/', NULL, $phone);

    // DISCARD A LEADING '1' FROM NUMBERS ENTERED LIKE 1-800-555-1212
    if (substr($phone,0,1) == '1') $phone = substr($phone,1);

    // IF LESS THAN TEN DIGITS, IT IS INVALID
    if (strlen($phone) < 10) return FALSE;

    // IF IT STARTS WITH '0' OR '1' IT IS INVALID, SECOND DIGIT CANNOT BE '9' (YET)
    if (substr($phone,0,1) == '0') return FALSE;
    if (substr($phone,0,1) == '1') return FALSE;
    if (substr($phone,1,1) == '9') return FALSE;

    // ISOLATE THE COMPONENTS OF THE PHONE NUMBER
    $ac = substr($phone,0,3); // AREA
    $ex = substr($phone,3,3); // EXCHANGE
    $nm = substr($phone,6,4); // NUMBER
    $xt = substr($phone,10);  // EXTENSION

    // ADD OTHER TESTS HERE AS MAY BE NEEDED - THESE ARE FOR LOCAL APPS
    if ($ac == '900') return FALSE;
    if ($ac == '976') return FALSE;
    if ($ex == '555') return FALSE;

    // IF NOT FORMATTED
    if (!$format) return $phone;

    // STANDARDIZE THE PRINTABLE FORMAT OF THE PHONE NUMBER LIKE 212-555-1212-1234
    $formatted_phone = $ac . $dlm . $ex . $dlm . $nm;
    if ($xt != '') $formatted_phone .= $dlm . $xt;
    return $formatted_phone;
}



// DEMONSTRATION OF THE FUNCTION IN ACTION.
if (!empty($_GET["p"]))
{
    // VALIDATE PHONE USING FUNCTION ABOVE
    if (!$phone = strtophone($_GET["p"], TRUE))
    {
        // FUNCTION RETURNS FALSE IF PHONE NUMBER IS UNUSABLE
        echo "BOGUS: {$_GET["p"]} ";
    }
    else
    {
        // SHOW THE FORMATTED PHONE
        echo "VALID: {$_GET["p"]} == $phone";
    }
}


// PUT UP A FORM TO TEST PHONE NUMBERS
function ph($p)
{
    echo "<br/><a href=\"{$_SERVER['PHP_SELF']}?p=" . urlencode($p) . "\">$p</a>" . PHP_EOL;
}

$form = <<<EOD
<form>
ENTER A PHONE NUMBER:
<input name="p" /><br/>
<input type="submit" />
</form>
TRY SOME OF THESE (CLICK OR COPY AND PASTE):
EOD;

echo $form;

ph('1-800-5551212');
ph('202-537-7560');
ph('202 537 7560');
ph('1-202-537-7560');
ph('(202) 537-7560');
ph('1.202.537.7560');
ph('123456789');
ph('703-356-5300 x2048');
ph('(212) 555-1212');
ph('1 + (212) 555-1212');
ph('1 (292) 226-7000');

Open in new window

Become a Certified Penetration Testing Engineer

This CPTE Certified Penetration Testing Engineer course covers everything you need to know about becoming a Certified Penetration Testing Engineer. Career Path: Professional roles include Ethical Hackers, Security Consultants, System Administrators, and Chief Security Officers.

Most Valuable Expert 2011
Top Expert 2016

Commented:
@skij (and anyone else coming across this question in the future): It is usually a good idea to test the solutions before accepting them.  In the instant case, the accepted solution will pass both $str1 and $str2.  The correct solution was available here:
http://www.experts-exchange.com/questions/28719388/PHP-Test-if-string-contains-only-numbers-dashes-parentheses-and-spaces.html#a40990071

Author

Commented:
Ray, thanks for your comments.  I solution I accepted provided a working regular expression that met the needs of my original post.  I tested the regular expression and it met my needs, which is why I accepted it as the solution.
Dave BaldwinFixer of Problems
Most Valuable Expert 2014

Commented:
Ray, I did check my code before I posted it.  I didn't put it in a loop like you did but it shows the correct results if you manually change the variable in the 'preg_match' line.

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial