0

I have a custom widget that will display the public feed from instagram profiles using the json response from the site. On my dev machine all is working fine but on tophost where the final wordpress installation is hosted, I have always a php error:

Invalid argument supplied for foreach() on line 60

I've checked the line, and it's relative to the processing of the returned array of data from Instagram, but it's strange because as I wrote there is no error on my local machine.

here is the code:

  public function widget( $args, $instance )
  {
    $url = 'https://instagram.com/'.$instance['username'].'/?__a=1';
    $ch = curl_init();
    curl_setopt( $ch, CURLOPT_URL, $url );
    curl_setopt( $ch, CURLOPT_HTTPHEADER, array('Accept: application/json') );
    curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
    curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, true );
    $feed = curl_exec($ch);
    curl_close($ch);
    $data = json_decode( $feed , true);
    ob_start();
    ?>
    <div class="jumbotron jumbotron-fluid ig-feed">
      <div class="container">
        <div class="row">
          <div class="col-sm-12 col-md-12 col-lg-12">
            <div class="swiper-container swiper-feed">
              <div class="swiper-wrapper">
            <?php
// this is the foreach() that is generating the error
              foreach( $data['graphql']['user']['edge_owner_to_timeline_media']['edges'] as $node ){
                foreach( $node as $img ){
                  echo '<div class="swiper-slide feed-img" style="background-image:url('.$img['display_url'].');"></div>';
                }
              }
            ?>
              </div>
            <div class="swiper-button-prev "></div>
            <div class="swiper-button-next"></div>
            </div>
          </div>
        </div>
      </div>
    </div>
    <?php
    echo ob_get_clean();
  }

I've checked the provider website and curl is enabled. Can be the problem in the csp I set on the function.php file?

  function http_headers()
  {
    header("Strict-Transport-Security: max-age=31536000; includeSubDomains");
    header("Set-Cookie: HttpOnly;Secure");
#    header("Content-Security-Policy: default-src 'self' 'unsafe-inline' https://www.youtube.com/; script-src 'self' 'unsafe-inline' https://www.youtube.com; img-src 'self' https://scontent-mxp1-1.cdninstagram.com; style-src 'self' 'unsafe-inline' https://scontent-mxp1-1.cdninstagram.com; font-src 'self' data:; object-src 'none';");
    header("X-Frame-Options: SAMEORIGIN");
    header("X-Xss-Protection: 1; mode=block");
    header("X-Content-Type-Options: nosniff");
    header("Referrer-Policy: strict-origin");
    header("X-Pingback: ");
    header("X-Powered-By: ");
  }
  add_action('send_headers', 'http_headers');

Thanks for the help.

NB: The server is running on php 7.2 under CGI/FastCGI

sisaln
  • 210
  • 4
  • 16
  • 1
    I notice you dont check the response from the curl before going adead and using it? – RiggsFolly Dec 21 '19 at 13:18
  • The response is valid, I can get the images url from any public feed without problems on my dev machine as I wrote. Instead, If I var_dump the `$feed` variable It will contain a string on the final host machine in production, but the `$data` variable is null like the data are not processed? – sisaln Dec 21 '19 at 13:23
  • 1
    So if `$data` is null, the `json_decode()` failed. So either there is no response returned OR it is not JSON OR the JSON is invalid – RiggsFolly Dec 21 '19 at 13:27
  • 1
    Add this code after the `curl_exec()` and tell us what is the error `if ($feed === false) { echo curl_error($ch) . PHP_EOL . curl_errno($ch); }` – RiggsFolly Dec 21 '19 at 13:49
  • ok, I will try and let you know – sisaln Dec 21 '19 at 13:53
  • 1
    I bet if you add this line `curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);` it will start to work. However that is not a great solution. – RiggsFolly Dec 21 '19 at 13:53
  • If I am right then read this https://stackoverflow.com/questions/28858351/php-ssl-certificate-error-unable-to-get-local-issuer-certificate – RiggsFolly Dec 21 '19 at 13:56
  • No error is logged, I just get a null `$data` variable after the cURL operations are done. – sisaln Dec 21 '19 at 14:02
  • @RiggsFolly ok, I will take a look and try implementing the option you suggested. – sisaln Dec 21 '19 at 14:02
  • No way to make the code work. the `$feed` variable contains a 40006 long string but it will not be processed or passed to `json_decode` – sisaln Dec 21 '19 at 14:09
  • `$instance['username']` is the variable that hold the username to load inside the url and is set from the wordpress widget backend. It's working fine – sisaln Dec 21 '19 at 14:18
  • I just tested against a freiends account and got a `length of feed string = 43247` so maybe this is as simple as a `memory_limit` issue. Did you check for error messages yet in the error logs – RiggsFolly Dec 21 '19 at 14:24
  • Add [error reporting](http://stackoverflow.com/questions/845021/) to the top of your file(s) _while testing_ right after your opening PHP tag for example ` – RiggsFolly Dec 21 '19 at 14:25
  • Tried, nothing is logged. I think that is a problem relative to the tophost hosting service that is blocking the request or something similar. I'm testing on another live server and all is working fine, the feed is loaded without problems. I will write a jQuery version of the widget to try solving the issue. Thanks for the help – sisaln Dec 21 '19 at 14:59

1 Answers1

-1

I had this error several times too. As the error says, the argument you are passing to the foreach is invalid. This means the array you are accessing does not exist or does not contain the correct entries you are refering to.

I would always check if the array contains the key or check if it is NOT NULL.

if ($data['graphql']['user']['edge_owner_to_timeline_media']['edges'] != NULL)
{
  //then parse it with foreach
}

Why this is working on local and not on remote server? Maybe the request you are sending is not working. Wrong access token ...?

davidev
  • 7,694
  • 5
  • 21
  • 56
  • There is non need for an access token, these are the info provided by instagram for every public profile. I need to try using `file_get_contents` to see the response, but the structure of the data is the same I have on my local machine. – sisaln Dec 21 '19 at 13:27
  • 4
    Would be better to first check if `$data` is actually NOT NULL and IS an Array, before attempting to look for something way down inside the array – RiggsFolly Dec 21 '19 at 13:29
  • @RiggsFolly I've done the check, and I've also tried using `file_get_contents`, the data are returned correctly, but for some reason the `$data` variable are not set when I pass it to the `json_parse()`. I think that there is some configuration on the host server that cause this beahviour – sisaln Dec 21 '19 at 13:44