title: json_decode syntax error 4 from valid json
body: <h2><strong>UPDATE: FINAL SOLUTION</strong></h2>
  <p>It turned out to be invisible characters afterall. Which characters exactly? I couldn't tell you.</p>
  <p>Here is a 1-liner that fixed the problem:</p>
  <pre><code>&lt;?php
  // get string from $_POST, 
  // wp_unslash it, 
  // then sanitize as text, 
  // then json_decode, 
  // and assign to variable as assoc. array ready for action
  $location = json_decode(sanitize_text_field(wp_unslash($_POST['acf']['field_621fa9e5511f3'])), true);
  
  // These are the default sanitization functions used when update_post_meta is fired. 
  // By default they:
  //   * Check for invalid UTF-8 (uses wp_check_invalid_utf8())
  //   * Converts single &lt; characters to entity
  //   * Strips all tags
  //   * Remove line breaks, tabs and extra white space
  //   * Strip octets
  ?&gt;
  </code></pre>
  <p>One or more of those things was causing the issue. It didn't seem like I needed to strip any invisible/special chars, but turns out I did.</p>
  <p>NOTE:
  None of these had any effect. The built-in WP functions above finally did the trick!</p>
  <pre><code>&lt;?php
  trim($_POST['acf']['field_621fa9e5511f3'])
  
  urlencode($_POST['acf']['field_621fa9e5511f3'])
  
  str_replace(array(&quot;\r&quot;, &quot;\n&quot;), &quot;&quot;, $_POST['acf']['field_621fa9e5511f3']);
  ?&gt;
  </code></pre>
  <h2><strong>UPDATE</strong></h2>
  <p>To get right to the issue at hand, it seems json_decode is not working when I pass it the $location string variable (with $_POST as the source), but works fine using the string itself (which validates fine on <a href="https://jsonlint.com" rel="nofollow noreferrer">https://jsonlint.com</a> and as @CBroe posted at <a href="https://3v4l.org/FSDnf" rel="nofollow noreferrer">https://3v4l.org/FSDnf</a>)</p>
  <pre><code>&lt;?php 
  
  global $_POST;
  
  $location = $_POST['acf']['field_621fa9e5511f3'];
  
  // var type
  echo gettype($location); 
  // returns: string
  
  // var_dump
  var_dump($location); 
  // returns: string(375) &quot;{&quot;lat&quot;:27.884301199999999,&quot;lng&quot;:-82.389221199999994,&quot;zoom&quot;:14,&quot;markers&quot;:[{&quot;label&quot;:&quot;Burts Road 6311, 33619 Tampa, Florida United States&quot;,&quot;default_label&quot;:&quot;Burts Road 6311, 33619 Tampa, Florida United States&quot;,&quot;lat&quot;:27.884189800000001,&quot;lng&quot;:-82.389353099999994}],&quot;address&quot;:&quot;Burts Road 6311, 33619 Tampa, Florida United States&quot;,&quot;layers&quot;:[&quot;OpenStreetMap.Mapnik&quot;],&quot;version&quot;:&quot;1.3.2&quot;}&quot;
  
  // echo string
  echo $location; 
  // returns: {&quot;lat&quot;:27.884301199999999,&quot;lng&quot;:-82.389221199999994,&quot;zoom&quot;:14,&quot;markers&quot;:[{&quot;label&quot;:&quot;Burts Road 6311, 33619 Tampa, Florida United States&quot;,&quot;default_label&quot;:&quot;Burts Road 6311, 33619 Tampa, Florida United States&quot;,&quot;lat&quot;:27.884189800000001,&quot;lng&quot;:-82.389353099999994}],&quot;address&quot;:&quot;Burts Road 6311, 33619 Tampa, Florida United States&quot;,&quot;layers&quot;:[&quot;OpenStreetMap.Mapnik&quot;],&quot;version&quot;:&quot;1.3.2&quot;} 
  
  // json_decode string as a variable
  var_dump(json_decode($location, true), json_last_error());
  // fails with error 4 for syntax
  
  // json_decode string itself
  var_dump(json_decode('{&quot;lat&quot;:27.884301199999999,&quot;lng&quot;:-82.389221199999994,&quot;zoom&quot;:14,&quot;markers&quot;:[{&quot;label&quot;:&quot;Burts Road 6311, 33619 Tampa, Florida United States&quot;,&quot;default_label&quot;:&quot;Burts Road 6311, 33619 Tampa, Florida United States&quot;,&quot;lat&quot;:27.884189800000001,&quot;lng&quot;:-82.389353099999994}],&quot;address&quot;:&quot;Burts Road 6311, 33619 Tampa, Florida United States&quot;,&quot;layers&quot;:[&quot;OpenStreetMap.Mapnik&quot;],&quot;version&quot;:&quot;1.3.2&quot;}', true), json_last_error());
  // works fine
  
  ?&gt;
  </code></pre>
  <p>Something about the $_POST data source/type because setting the string manually works fine:</p>
  <pre><code>// set string variable
  $location = '{&quot;lat&quot;:27.884301199999999,&quot;lng&quot;:-82.389221199999994,&quot;zoom&quot;:14,&quot;markers&quot;:[{&quot;label&quot;:&quot;Burts Road 6311, 33619 Tampa, Florida United States&quot;,&quot;default_label&quot;:&quot;Burts Road 6311, 33619 Tampa, Florida United States&quot;,&quot;lat&quot;:27.884189800000001,&quot;lng&quot;:-82.389353099999994}],&quot;address&quot;:&quot;Burts Road 6311, 33619 Tampa, Florida United States&quot;,&quot;layers&quot;:[&quot;OpenStreetMap.Mapnik&quot;],&quot;version&quot;:&quot;1.3.2&quot;}';
  
  //  var_dump json_decode
  var_dump(json_decode($location, true), json_last_error()); 
  // works fine
  </code></pre>
  <p>I'm not sure where &quot;the break&quot; exists. From everything I can see this should work fine, but it doesn't:</p>
  <pre><code>&lt;?php
  global $_POST;
  
  // get string from $_POST, json_decode() it, and then var_dump
  var_dump(json_decode($_POST['acf']['field_621fa9e5511f3'], true), json_last_error());
  // fails with error 4 for syntax
  ?&gt;
  </code></pre>
  <h2><strong>ORIGINAL POST BELOW</strong></h2>
  <p>Lots of other topics with a similar problem, but none of the solutions have worked for me.</p>
  <p>I have VALID JSON data that I grab from $_POST when a Wordpress custom post_type is added/updated. The purpose is to use some of the JSON data for other specific custom fields on each save. Here is some example JSON data grabbed:</p>
  <pre><code>{
      &quot;lat&quot;:27.884301199999999,
      &quot;lng&quot;:-82.389221199999994,
      &quot;zoom&quot;:12,
      &quot;markers&quot;:[
          {
              &quot;label&quot;:&quot;Burts Road 6311, 33619 Tampa, Florida United States&quot;,
              &quot;default_label&quot;:&quot;Burts Road 6311, 33619 Tampa, Florida United States&quot;,
              &quot;lat&quot;:27.884189800000001,
              &quot;lng&quot;:-82.389353099999994
          }
      ],
      &quot;address&quot;:&quot;Burts Road 6311, 33619 Tampa, Florida United States&quot;,
      &quot;layers&quot;:[&quot;OpenStreetMap.Mapnik&quot;],
      &quot;version&quot;:&quot;1.3.2&quot;
  }
  </code></pre>
  <p>It validates perfectly fine at <a href="https://jsonlint.com" rel="nofollow noreferrer">https://jsonlint.com</a></p>
  <p>When I try decode it, json_last_error() shows &quot;4&quot; for &quot;JSON_ERROR_SYNTAX&quot;. The relevant code in my function looks like this:</p>
  <pre><code>&lt;?php
      global $_POST;
          
      // get JSON data from $_POST
      $location = $_POST['acf']['field_621fa9e5511f3']
  
      /* Example JSON data for &quot;$location&quot; is shown above */
        
      // get assoc. array from JSON
      $location_decode = json_decode( $location, true );
       
      /* here's where my custom code would go to do all of my processing */
       
      // add/update values to post_meta table after all processing
      update_post_meta( $post_id, 'JSON_Decoded', $location_decode );
      update_post_meta( $post_id, 'JSON_Last_error', json_last_error() );
  ?&gt;
  </code></pre>
  <p>&quot;$location_decode&quot; is always empty (which means the 'JSON_Decoded' meta field is also always empty).</p>
  <p><strong>var_dump of $location</strong></p>
  <pre><code>string(375) &quot;{&quot;lat&quot;:27.884301199999999,&quot;lng&quot;:-82.389221199999994,&quot;zoom&quot;:14,&quot;markers&quot;:[{&quot;label&quot;:&quot;Burts Road 6311, 33619 Tampa, Florida United States&quot;,&quot;default_label&quot;:&quot;Burts Road 6311, 33619 Tampa, Florida United States&quot;,&quot;lat&quot;:27.884189800000001,&quot;lng&quot;:-82.389353099999994}],&quot;address&quot;:&quot;Burts Road 6311, 33619 Tampa, Florida United States&quot;,&quot;layers&quot;:[&quot;OpenStreetMap.Mapnik&quot;],&quot;version&quot;:&quot;1.3.2&quot;}&quot; 
  </code></pre>
  <p><strong>Solutions Tried:</strong></p>
  <p>I tried removing some of the invisible special characters like BOM, but since the source of the data is $_POST and not a file, these kind of invisible characters shouldn't really matter:</p>
  <pre><code>&lt;?php
      if (0 === strpos(bin2hex($location), 'efbbbf')) {
          $location = substr($location, 3);
      }
  ?&gt;
  </code></pre>
  <p>I tried setting encoding to UTF8 prior to JSON decode, even though the UTF8 is the default encoding for the site and DB. 2 methods tried, and both had no effect:</p>
  <pre><code>&lt;?php
      // method #1
      $location = utf8_encode($_POST['acf']['field_621fa9e5511f3']);
  
      // method #2
      $location = mb_convert_encoding($_POST['acf']['field_621fa9e5511f3'], &quot;UTF-8&quot;, &quot;UTF-8&quot;); 
  ?&gt;
  </code></pre>
  <p>I've been messing with it for hours and now I'm reaching out for help out of frustration.</p>
  <p>What is wrong with the sample JSON data syntax and/or how can I get it to pass JSON_decode's syntax checks?</p>