phpstrpos

Error with strpos(): Argument #1 ($haystack) must be of type string, array given


I'm trying to fix a problem with a Wordpress Plugin. I've received the following error:

strpos(): Argument #1 ($haystack) must be of type string, array given

The code i'm getting the error from is as following:

// woocommerce field
if ( $field === '_gallery_images' ) {

    // set the image prefix if there is one
    $prefix = '';
    if ( $tmp_field['prefix'] !== '' ) {
        $prefix = $tmp_field['prefix'];
    }

    // if value is not an array, try to create one
    // this may be due to comma separated urls or space separated
    if ( ! is_array( $our_value ) ) {

        // if we have comma separated URL's, create an array
        if ( strpos( $our_value, ',' ) !== false ) {
            $array = explode( ',', $our_value );
            if ( is_array( $array ) ) {
                $our_value = $array;
            }
        }

        // if we have space separated URL's, create an array
        // This next line is generating the error
        if ( strpos( $our_value, ' ' ) !== false ) {
            $array = explode( ' ', $our_value );
            if ( is_array( $array ) ) {
                $our_value = $array;
            }
        }

        // if we have newline separated URL's, create an array
        if ( strpos( $our_value, "\n" ) !== false ) {
            $array = explode( "\n", $our_value );
            if ( is_array( $array ) ) {
                $our_value = $array;
            }
        }
}

He gets this value from an API and tries to explode the sep urls:

11104_105-b.jpg, 11104_105.jpg, 11104_105-c.jpg, 11104_105-d.jpg

I've updated the post with the full code section, sorry.

The function that cointan an error is the following:

if ( strpos( $our_value, ' ' ) !== false ) {

Here is the full log about the error

PHP Fatal error:  Uncaught TypeError: strpos(): Argument #1 ($haystack) must be of type string, array given in /home2/miriamcoelho/public_html/wp-content/plugins/wpgetapi-api-to-posts/includes/class-wpgetapi-api-to-posts-importer.php:1703Stack 
trace:#0 /home2/miriamcoelho/public_html/wp-content/plugins/wpgetapi-api-to-posts/includes/class-wpgetapi-api-to-posts-importer.php(1703): strpos(Array, ' ')
#1 /home2/miriamcoelho/public_html/wp-content/plugins/wpgetapi-api-to-posts/includes/class-wpgetapi-api-to-posts-importer.php(808): WPGetAPI_API_To_Posts_Importer->map_fields_and_add_data(Array, Array)
#2 /home2/miriamcoelho/public_html/wp-content/plugins/wpgetapi-api-to-posts/includes/class-wpgetapi-api-to-posts-importer.php(1065): WPGetAPI_API_To_Posts_Importer->create_posts(Array, Array, Array, '1207067011')
#3 /home2/miriamcoelho/public_html/wp-content/plugins/wpgetapi-api-to-posts/includes/class-wpgetapi-api-to-posts-importer.php(956): WPGetAPI_API_To_Posts_Importer->maybe_add_delete_posts_ajax(Array, '1207067011', Array)
#4 /home2/miriamcoelho/public_html/wp-includes/class-wp-hook.php(324): WPGetAPI_API_To_Posts_Importer->run_post_creator_ajax('')
#5 /home2/miriamcoelho/public_html/wp-includes/class-wp-hook.php(348): WP_Hook->apply_filters('', Array)
#6 /home2/miriamcoelho/public_html/wp-includes/plugin.php(517): WP_Hook->do_action(Array)
#7 /home2/miriamcoelho/public_html/wp-admin/admin-ajax.php(192): do_action('wp_ajax_wpgetap...')
#8 {main}thrown in /home2/miriamcoelho/public_html/wp-content/plugins/wpgetapi-api-to-posts/includes/class-wpgetapi-api-to-posts-importer.php on line 1703

I don't know how to fix this, and the plugin owner does not seem to be interested in a solution.


Solution

  • Where the problem lies

    You have one big if that tests for the need to convert a string to array, determining if you enter your 3-stage attempt to convert.

    Each stage expects a string in input (strpos will be uncompromising about it), and, if succeeding, will transform $our_value to an array, to be passed to the next stage.

    But… Wait! Didn't we say that the next stage too wanted a string as input? And that the just-transformed $our_value is now an array?

    What you can do

    You should a minima add your if(!is_array($our_value)) protection before each stage ("convert if not already converted").

    What you can do better

    But this first solution still has a problem: in the example you gave, 11104_105-b.jpg, 11104_105.jpg, 11104_105-c.jpg, 11104_105-d.jpg, we have both a comma and a space. How would it behave?
    First it will split against commas, letting the spaces in place (thus you'll have [ "11104_105-b.jpg", " 11104_105.jpg", … ]).
    And with our newly introduced protection, those spaces will stay forever.

    The ideal solution would be to detect "any serie of one or more space, comma, or newline".
    Well, good news: you can use regular expressions to that, replacing explode by preg_split.
    Replace your whole if ( ! is_array( $our_value ) ) { … } block by:

    if ( ! is_array( $our_value ) ) { // Or if ( is_string( $our_value ) ) {
        $our_value = preg_split('[\s,]+', $our_value);
    }
    

    And… That's all!

    Some explanations: