Reputation: 11225
json_encode
a PHP object that has private propertiesjson_decode
the PHP object in the AJAX URL to which the request is sentOn step 3, json_last_error is returning 3 (JSON_ERROR_CTRL_CHAR Control character error, possibly incorrectly encoded
)
class Stream {
private $limit;
private $type;
private $sort;
private $offset=0;
private $userID;
private $catID;
private $content = array();
private $num_posts;
function __construct(){
$a = func_get_args();
$i = func_num_args();
if (method_exists($this,$f='__construct'.$i)) {
call_user_func_array(array($this,$f),$a);
}
}
function __construct5($limit, $type, $sort, $userID, $catID){
$this->limit = $limit;
$this->type = $type;
$this->sort = $sort;
$this->userID = $userID;
$this->catID = $catID;
//$this->num_posts = $this->retrieveTotal();
//$this->setContent();
}
function __get($name) {
if(isset($this->$name)){
return $this->$name;
}
}
public function encodeJSON(){
foreach ($this as $key => $value){
if($key != 'content'){
$json->$key = $value;
}
}
return json_encode($json);
}
public function decodeJSON($json_str){
$json = json_decode($json_str, true);
echo '<br>error: '.json_last_error();
foreach ($json as $key => $value){
$this->$key = $value;
}
}
}
//create the object to be encoded
$strm = new Stream(5, 'toc', ' ', 1, ' ');
/*this test works
$d=$strm->encodeJSON();
$st = new Stream();
$st->decodeJSON($d);
*/
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
//load more posts
$("#active").live("click", function() {
var stream= '<?= $strm->encodeJSON();?>';
var dataString = 'stream='+stream;
var request = $.ajax({
type: "POST",
url: "ajax/loadmore.php",
data: dataString,
beforeSend:function(data){
$('.load-more').html('<img src="ajax/loader.gif" alt="Loading..." />');
},
success: function(html) {
$('#active').remove();
$('#stream').append(html);
}
});
//ajax error reporting
request.fail(function(jqXHR, textStatus) {
$('#active').html(textStatus);
});
});
</script>
<a class='load-more' id='active'>load more posts</a>
require_once'../../classes/stream.class.php';
$strm = new Stream();
$strm->decodeJSON($_POST['stream']);
This snippet of code
$d=$strm->encodeJSON();
$st = new Stream();
$st->decodeJSON($d);
works fine. That would lead me to believe that AJAX is interfering with the decoding.
I have also tried changing $json = json_decode($json_str, true);
to $json = json_decode(utf8_encode($json_str), true);
and nothing changes.
NOTE: suggesting that I make the class properties public is NOT a solution
EDIT: when I echo the string, {
"limit": "5",
"type": "toc",
"sort": " ",
"offset": "0",
"userID": "3",
"catID": " ",
"num_posts": "2"
}
being sent to decodeJSON it tests as valid
This screenshot shows the arg $json_str that is being sent to decodeJSON($json_str) and the error code.
Upvotes: 2
Views: 4390
Reputation: 11225
After much trial and error I figured out the issue. When I was instantiating the Stream object
that was to be encoded, instead of using 1
i was using $userID
which was being cast as a string and messing with the URI encoding
stream=%7B%22limit%22%3A%225%22%2C%22type%22%3A%22toc%22%2C%22sort%22%3A%22%20%22%2C%22offset%22%3A%220%22%2C%22userID%22%3A%223%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%22%2C%22catID%22%3A%22%20%22%2C%22num_posts%22%3A%222%22%7D
I'm not really sure WHY it behaves that way, but the solution is casting the $userID as an integer. so:
$strm = new Stream(5, 'toc', ' ', (int)$userID, ' ');
The URI encoding changes to:
stream=%7B%22limit%22%3A%225%22%2C%22type%22%3A%22toc%22%2C%22sort%22%3A%22%20%22%2C%22offset %22%3A%220%22%2C%22userID%22%3A%223%22%2C%22catID%22%3A%22%20%22%2C%22num_posts%22%3A%222%22%7D
and json_decode return an array.
Upvotes: 1
Reputation: 7369
JSON_ERROR_CTRL_CHAR
The reason it's returning JSON_ERROR_CTRL_CHAR
is not because of character encoding (ie, utf8 or iso). It encounters this error when data has been incorrectly encoded and the resulting string is not valid JSON. If you're mixing single quotes '
and double quotes "
it may interfere with the encoding process as well, it is important to be consistent.
With that being said,
It most likely returns the error because you're not sending any actual data in the first place. You're sending an empty string through the request. Well, not really, you're actually sending the string
<?= $strm->encodeJSON();?>
which then becomes
json_encode("<?= $strm->encodeJSON();?>");
in your loadmore.php.
But it would be empty anyway if you used the correct php tag <?php ?>
because you're not echoing anything.
Change
var stream= '<?= $strm->encodeJSON();?>';
to a proper php tag, and also make sure you actually output something, otherwise stream
will just be an empty string.
var stream= '<?php echo $strm->encodeJSON(); ?>';
And it should work properly.
Generally, when sending data through AJAX you should encodeURIComponent()
it to escape any special characters.
data: "stream="+encodeURIComponent(stream),
$json = json_decode(urldecode($json_str), true);
.live
is depracated
The .live
function is deprecated as of 1.7, you should now use the function .on
to attach event handlers. In your case, you would be better off just using the shorthand function .click()
.
links must have href
<a>
tags must have a href attribute, otherwise it won't be a link and you might as well be using a <div>
if you're not gonna use it. At a minimum you should have href="#"
and then add an event.preventDefault()
.
File names
When you name your files, try to stay away from using periods stream.class.php
, they're accidents waiting to happen. Some systems (especially older), won't interpret them properly and you're going to have a hard time renaming all of them. Standard convention suggests using underscore or hyphens for stable file systems.
This works on my end (with all files in the same folder)
HTML default (index.php)
<?php
include_once("stream.php");
?>
<!DOCTYPE html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
//load more posts
$(document).ready(function(){
$("#active").click(function(e) {
e.preventDefault();
var stream = '<?php echo $strm->encodeJSON();?>';
var dataString = stream;
var request = $.ajax({
type: "POST",
url: "loadmore.php",
data: "stream="+encodeURIComponent(stream),
dataType: "html",
beforeSend:function(data){
$('.load-more').html('<img src="ajax-loader(1).gif" alt="Loading..." />');
},
success: function(html) {
$('#active').remove();
$('#stream').append(html);
}
});
//ajax error reporting
request.fail(function(jqXHR, textStatus) {
$('#active').html(textStatus);
});
});
});
</script>
</head>
<body>
<a href="#" class='load-more' id='active'>load more posts</a>
<div id="stream"></div>
</body>
</html>
stream.php
<?php
class Stream {
private $limit;
private $type;
private $sort;
private $offset=0;
private $userID;
private $catID;
private $content = array();
private $num_posts;
function __construct(){
$a = func_get_args();
$i = func_num_args();
if (method_exists($this,$f='__construct'.$i)) {
call_user_func_array(array($this,$f),$a);
}
}
function __construct5($limit, $type, $sort, $userID, $catID){
$this->limit = $limit;
$this->type = $type;
$this->sort = $sort;
$this->userID = $userID;
$this->catID = $catID;
//$this->num_posts = $this->retrieveTotal();
//$this->setContent();
}
function __get($name) {
if(isset($this->$name)){
return $this->$name;
}
}
public function encodeJSON(){
foreach ($this as $key => $value){
if($key != 'content'){
$json->$key = $value;
}
}
return json_encode($json);
}
public function decodeJSON($json_str){
$json = json_decode(urldecode($json_str), true);
foreach ($json as $key => $value){
$this->$key = $value;
}
}
}
//create the object to be encoded
$strm = new Stream(5, 'toc', ' ', 1, ' ');
?>
loadmore.php
<?php
include_once('stream.php');
$strm = new Stream();
$strm->decodeJSON($_POST['stream']);
//Output a private property
echo $strm->__get("type");
?>
Upvotes: 3
Reputation: 1416
JSON only support UTF-8 for strings. So you must encode all strings in UTF-8 before doing json_encode. What seems to happend here (I don't understand all your code) is that you have a string with no-UTF8 that looks to json_encode like "control characters".
Upvotes: 0