Search code examples
phpstringsearchstrposordinals

Need a working code example where a non-string value is passed in $needle parameter of strpos() function


I'm using PHP 7.2.11 on my machine that runs on Windows 10 Home Single Language 64-bit Operating System.

I came across the manual page of strpos() function's needle parameter

There it has been written as

needle

If needle is not a string, it is converted to an integer and applied as the ordinal value of a character.

I didn't understand the meaning of above statement about needle parameter.

Can someone please explain me the meaning of the statement about needle parameter from the PHP manual along with the working code example where a non-string value is passed in $needle parameter of strpos() function.

How the conversion to the type integer is done and how it is applied as the ordinal value of a character?

I couldn't find such example anywhere in the manual or any other website.

It would be better if the working coding example along with the offset parameter is also provided.

Thank You.


Solution

  • $haystack = "maio290";
    $needle = ord("a");
    
    var_dump(strpos($haystack,$needle));
    

    Outputs: int(1)

    Why? The ordinal value of a character is equal to a number you can find in several ASCII tables. For example, the character "a" is equal to the integer of 97.

    Here is the source code of PHP (or the stuff you need to understand the function strpos):

    static int php_needle_char(zval *needle, char *target)
    {
        switch (Z_TYPE_P(needle)) {
            case IS_LONG:
                *target = (char)Z_LVAL_P(needle);
                return SUCCESS;
            case IS_NULL:
            case IS_FALSE:
                *target = '\0';
                return SUCCESS;
            case IS_TRUE:
                *target = '\1';
                return SUCCESS;
            case IS_DOUBLE:
                *target = (char)(int)Z_DVAL_P(needle);
                return SUCCESS;
            case IS_OBJECT:
                *target = (char) zval_get_long(needle);
                return SUCCESS;
            default:
                php_error_docref(NULL, E_WARNING, "needle is not a string or an integer");
                return FAILURE;
        }
    }
    
    PHP_FUNCTION(strpos)
    {
        zval *needle;
        zend_string *haystack;
        const char *found = NULL;
        char  needle_char[2];
        zend_long  offset = 0;
    
        ZEND_PARSE_PARAMETERS_START(2, 3)
            Z_PARAM_STR(haystack)
            Z_PARAM_ZVAL(needle)
            Z_PARAM_OPTIONAL
            Z_PARAM_LONG(offset)
        ZEND_PARSE_PARAMETERS_END();
    
        if (offset < 0) {
            offset += (zend_long)ZSTR_LEN(haystack);
        }
        if (offset < 0 || (size_t)offset > ZSTR_LEN(haystack)) {
            php_error_docref(NULL, E_WARNING, "Offset not contained in string");
            RETURN_FALSE;
        }
    
        if (Z_TYPE_P(needle) == IS_STRING) {
            if (!Z_STRLEN_P(needle)) {
                php_error_docref(NULL, E_WARNING, "Empty needle");
                RETURN_FALSE;
            }
    
            found = (char*)php_memnstr(ZSTR_VAL(haystack) + offset,
                                Z_STRVAL_P(needle),
                                Z_STRLEN_P(needle),
                                ZSTR_VAL(haystack) + ZSTR_LEN(haystack));
        } else {
            if (php_needle_char(needle, needle_char) != SUCCESS) {
                RETURN_FALSE;
            }
            needle_char[1] = 0;
    
            php_error_docref(NULL, E_DEPRECATED,
                "Non-string needles will be interpreted as strings in the future. " \
                "Use an explicit chr() call to preserve the current behavior");
    
            found = (char*)php_memnstr(ZSTR_VAL(haystack) + offset,
                                needle_char,
                                1,
                                ZSTR_VAL(haystack) + ZSTR_LEN(haystack));
        }
    
        if (found) {
            RETURN_LONG(found - ZSTR_VAL(haystack));
        } else {
            RETURN_FALSE;
        }
    }
    

    Found here: https://github.com/php/php-src/blob/master/ext/standard/string.c

    That means:

    long: Get a long value and cast it to a char.

    null or false: returns 0 (as char)

    true: returns 1 (as char)

    double: Get a double value, cast it into integer (which means, all parts after the dot are lost) and then cast it into a char.

    object: Get a long (? from the object and cast it to a char.

    I'm not that deep into C or the Zend-Engine, and therefore I might have explained something wrong. But that should be actually what you were looking for.