quick question i really need some help, i re-formatting some json to get it into a javascript var, i got it working with json_encode but i need it to output ' symbol instead of the " symbol, is there a way to do that
i need it to be like this (using the ' symbol)
{
title:'Greeting',
mp3:'http://www.godsgypsychristianchurch.net/music/Atlanta%20GA/Dey%20duma%20amensa/01%20Greeting.mp3',
buy:'http://www.godsgypsychristianchurch.net/music/Atlanta%20GA/Dey%20duma%20amensa/01%20Greeting.mp3',
price:'Download',
duration:'',
cover:'http://godsgypsychristianchurch.net/music_artwork/DEFAULT_COVER.png'},
My Code:
foreach ($json['rows'] as $row) {
if ($_GET['churchname'] == $row[doc]['album']) {
$songCount = 0;
foreach ($row['doc']['tracks'] as $song) {
++$songCount;
$arr = array(
"title" => "{$song['name']}",
"mp3" => "{$songUrl}",
"buy" => "{$songUrl}",
"price" => "Download",
"duration" => "",
"cover" => "{$row['doc']['artwork']}",
);
echo json_encode($arr);
}
}
}
exit;
1) You can't get it to use the ' ', as the specification for valid-JSON requires " ", so any program expecting to parse your string from JSON to an object in JS/PHP/etc, is going to error out on you
2) Why? JS doesn't care which one you use, one way or another, and if you're doing something on the server-side, leave it as a multi-dimensional (potentially associative) array.
3) If it's for the purpose of including " " inside of your actual string, then escape them with \, like so:
$myString = "This is my \"double-quoted\" string";
$myString === 'This is my "double-quoted" string';
$myString === "This is my " . '"double-quoted"' . "string";
If you are concatenating strings together, and one of those strings already contains double-quotes within the string itself, then your language will automatically ensure they're escaped.
I'd be happy to help further, but I'd need to know the "Why?" part.
Related
Sample code:
<?php
$json = "['foo', 'bar']";
var_dump( json_decode($json) );
It works with PHP 5.5.3 but it fails for lower PHP's versions
It works on my machine with PHP 5.5.3 but it fails everywhere else.
I know it is incorrect JSON but my webservice gives me JSON with ' symbols together with "
['foo', "bar", {'test': "crazy \"markup\""}]
Sandbox
How to parse JSON data with apostrophes in PHP 5.3? Obviously original JSON I want to parse is more complex.
(I can't upgrade my PHP on production server neither get proper JSON from webservice)
Here's an alternative solution to this problem:
function fixJSON($json) {
$regex = <<<'REGEX'
~
"[^"\\]*(?:\\.|[^"\\]*)*"
(*SKIP)(*F)
| '([^'\\]*(?:\\.|[^'\\]*)*)'
~x
REGEX;
return preg_replace_callback($regex, function($matches) {
return '"' . preg_replace('~\\\\.(*SKIP)(*F)|"~', '\\"', $matches[1]) . '"';
}, $json);
}
This approach is more robust than h2ooooooo's function in two respects:
It preserves double quotes occurring in a single quoted string, by applying additional escaping to them. h2o's variant will replace them with double quotes instead, thus changing the value of the string.
It will properly handle escaped double quotes \", for which h2o's version seems to go into an infinite loop.
Test:
$brokenJSON = <<<'JSON'
['foo', {"bar": "hel'lo", "foo": 'ba"r ba\"z', "baz": "wor\"ld ' test"}]
JSON;
$fixedJSON = fixJSON($brokenJSON);
$decoded = json_decode($fixedJSON);
var_dump($fixedJSON);
print_r($decoded);
Output:
string(74) "["foo", {"bar": "hel'lo", "foo": "ba\"r ba\"z", "baz": "wor\"ld ' test"}]"
Array
(
[0] => foo
[1] => stdClass Object
(
[bar] => hel'lo
[foo] => ba"r ba"z
[baz] => wor"ld ' test
)
)
Here's a simple parser that'll fix your quotes for you. If it encounters a ' quote which isn't in a double quote ", it'll assume that it's wrong and replace the double quotes inside of that quote, and turn the quote enclosured into double quotes:
Example:
<?php
function fixJSON($json) {
$newJSON = '';
$jsonLength = strlen($json);
for ($i = 0; $i < $jsonLength; $i++) {
if ($json[$i] == '"' || $json[$i] == "'") {
$nextQuote = strpos($json, $json[$i], $i + 1);
$quoteContent = substr($json, $i + 1, $nextQuote - $i - 1);
$newJSON .= '"' . str_replace('"', "'", $quoteContent) . '"';
$i = $nextQuote;
} else {
$newJSON .= $json[$i];
}
}
return $newJSON;
}
$brokenJSON = "['foo', {\"bar\": \"hel'lo\", \"foo\": 'ba\"r'}]";
$fixedJSON = fixJSON( $brokenJSON );
var_dump($fixedJSON);
print_r( json_decode( $fixedJSON ) );
?>
Output:
string(41) "["foo", {"bar": "hel'lo", "foo": "ba'r"}]"
Array
(
[0] => foo
[1] => stdClass Object
(
[bar] => hel'lo
[foo] => ba'r
)
)
DEMO
NikiCs´ answer is already spot on. Your input seems to be manually generated, so it's entirely possible that within ' single quoted strings, you'll receive unquoted " doubles. A regex assertion is therefore advisable instead of a plain search and replace.
But there are also a few userland JSON parsers which support a bit more Javascript expression syntax. It's probably best to speak of JSOL, JavaScript Object Literals, at this point.
PEARs Services_JSON
Services_JSON can decode:
unquoted object keys
and strings enclosed in single quotes.
No additional options are required, just = (new Services_JSON)->decode($jsol);
up_json_decode() in upgradephp
This was actually meant as fallback for early PHP versions without JSON extension. It reimplements PHPs json_decode(). But there's also the upgrade.php.prefixed version, which you'd use here.
It introduces an additional flag JSON_PARSE_JAVASCRIPT.
up_json_decode($jsol, false, 512, JSON_PARSE_JAVASCRIPT);
And I totally forgot about mentionind this in the docs, but it also supports single-quoted strings.
For instance:
{ num: 123, "key": "value", 'single': 'with \' and unquoted " dbls' }
Will decode into:
stdClass Object
(
[num] => 123
[key] => value
[single] => with ' and unquoted " double quotes
)
Other options
JasonDecoder by #ArtisticPhoenix does support unquoted keys and literals, though no '-quoted strings. It's easy to understand or extend however.
YAML (1.2) is a superset of JSON, and most parsers support both unquoted keys or single-quoted strings. See also PHP YAML Parsers
Obviously any JSOL tokenizer/parser in userland is measurably slower than just preprocessing malformed JSON. If you expect no further gotchas from your webservice, go for the regex/quote conversion instead.
One solution would be to build a proxy using NodeJS. NodeJS will handle the faulty JSON just fine and return a clean version:
johan:~ # node
> JSON.stringify(['foo', 'bar']);
'["foo","bar"]'
Maybe write a simple Node script that accepts the JSON data as STDIN and returns the validated JSON to STDOUT. That way you can call it from PHP.
The downside is that your server would need NodeJS. Not sure if that is a problem for you.
If you know that PHP 5.5.+ will parse this JSON gracefully, I would pipe the web service responses trough a proxy script on a PHP5.5+ web server, which sanitizes the responses for lower versions - meaning just echo json_encode(json_decode($response)); That's a stable and reliable approach.
If you make the web service URL configurable trough a config value, it will work for lower versions by accessing the proxy, in higher versions by accessing the web service directly.
A fast solution could be str_replace("'","\"",$string). This depends on many things, but I think you could give it a try.
You could use (and probably modify/extend) a library to build an AST from the supplied JSON and replace the single quotes with double quotes.
https://github.com/Seldaek/jsonlint/blob/master/src/Seld/JsonLint/Lexer.php
Might be a good start.
Can I safely use explode() on a multi-byte string, specifically UTF8? Or do I need to use mb_split()?
If mb_split(), then why?
A multi-byte string is still just a string, and explode would happily split it on whatever delimiter you provide. My guess is that they will probably behave identically under most circumstances. If you are concerned about a particular situation, consider using this test script:
<?php
$test = array(
"ὕβρις",
"путин бандит",
"Дерипаска бандит",
"Трамп наша сука"
);
$delimiter = "д";
foreach($test as $t) {
$explode = explode($delimiter, $t);
echo "explode: " . implode("\t", $explode) . "\n";
$split = mb_split($delimiter, $t);
echo "split : " . implode("\t", $split) . "\n\n";
if ($explode != $split) {
throw new Exception($t . " splits differently!");
}
}
echo "script complete\n";
It's worth pointing out that both explode() and mb_split() have the exact same parameter list -- without any reference to language or character encoding. You should also realize that how your strings are defined in PHP depend on where and how you obtain your delimiter and the string to be exploded/split. Your strings might come from a text or csv file, a form submission in a browser, an API call via javascript, or you may define those strings right in your PHP script as I have here.
I might be wrong, but I believe that both functions will work by looking for instances of the delimiter in the string to be exploded and will split them.
Sample code:
<?php
$json = "['foo', 'bar']";
var_dump( json_decode($json) );
It works with PHP 5.5.3 but it fails for lower PHP's versions
It works on my machine with PHP 5.5.3 but it fails everywhere else.
I know it is incorrect JSON but my webservice gives me JSON with ' symbols together with "
['foo', "bar", {'test': "crazy \"markup\""}]
Sandbox
How to parse JSON data with apostrophes in PHP 5.3? Obviously original JSON I want to parse is more complex.
(I can't upgrade my PHP on production server neither get proper JSON from webservice)
Here's an alternative solution to this problem:
function fixJSON($json) {
$regex = <<<'REGEX'
~
"[^"\\]*(?:\\.|[^"\\]*)*"
(*SKIP)(*F)
| '([^'\\]*(?:\\.|[^'\\]*)*)'
~x
REGEX;
return preg_replace_callback($regex, function($matches) {
return '"' . preg_replace('~\\\\.(*SKIP)(*F)|"~', '\\"', $matches[1]) . '"';
}, $json);
}
This approach is more robust than h2ooooooo's function in two respects:
It preserves double quotes occurring in a single quoted string, by applying additional escaping to them. h2o's variant will replace them with double quotes instead, thus changing the value of the string.
It will properly handle escaped double quotes \", for which h2o's version seems to go into an infinite loop.
Test:
$brokenJSON = <<<'JSON'
['foo', {"bar": "hel'lo", "foo": 'ba"r ba\"z', "baz": "wor\"ld ' test"}]
JSON;
$fixedJSON = fixJSON($brokenJSON);
$decoded = json_decode($fixedJSON);
var_dump($fixedJSON);
print_r($decoded);
Output:
string(74) "["foo", {"bar": "hel'lo", "foo": "ba\"r ba\"z", "baz": "wor\"ld ' test"}]"
Array
(
[0] => foo
[1] => stdClass Object
(
[bar] => hel'lo
[foo] => ba"r ba"z
[baz] => wor"ld ' test
)
)
Here's a simple parser that'll fix your quotes for you. If it encounters a ' quote which isn't in a double quote ", it'll assume that it's wrong and replace the double quotes inside of that quote, and turn the quote enclosured into double quotes:
Example:
<?php
function fixJSON($json) {
$newJSON = '';
$jsonLength = strlen($json);
for ($i = 0; $i < $jsonLength; $i++) {
if ($json[$i] == '"' || $json[$i] == "'") {
$nextQuote = strpos($json, $json[$i], $i + 1);
$quoteContent = substr($json, $i + 1, $nextQuote - $i - 1);
$newJSON .= '"' . str_replace('"', "'", $quoteContent) . '"';
$i = $nextQuote;
} else {
$newJSON .= $json[$i];
}
}
return $newJSON;
}
$brokenJSON = "['foo', {\"bar\": \"hel'lo\", \"foo\": 'ba\"r'}]";
$fixedJSON = fixJSON( $brokenJSON );
var_dump($fixedJSON);
print_r( json_decode( $fixedJSON ) );
?>
Output:
string(41) "["foo", {"bar": "hel'lo", "foo": "ba'r"}]"
Array
(
[0] => foo
[1] => stdClass Object
(
[bar] => hel'lo
[foo] => ba'r
)
)
DEMO
NikiCs´ answer is already spot on. Your input seems to be manually generated, so it's entirely possible that within ' single quoted strings, you'll receive unquoted " doubles. A regex assertion is therefore advisable instead of a plain search and replace.
But there are also a few userland JSON parsers which support a bit more Javascript expression syntax. It's probably best to speak of JSOL, JavaScript Object Literals, at this point.
PEARs Services_JSON
Services_JSON can decode:
unquoted object keys
and strings enclosed in single quotes.
No additional options are required, just = (new Services_JSON)->decode($jsol);
up_json_decode() in upgradephp
This was actually meant as fallback for early PHP versions without JSON extension. It reimplements PHPs json_decode(). But there's also the upgrade.php.prefixed version, which you'd use here.
It introduces an additional flag JSON_PARSE_JAVASCRIPT.
up_json_decode($jsol, false, 512, JSON_PARSE_JAVASCRIPT);
And I totally forgot about mentionind this in the docs, but it also supports single-quoted strings.
For instance:
{ num: 123, "key": "value", 'single': 'with \' and unquoted " dbls' }
Will decode into:
stdClass Object
(
[num] => 123
[key] => value
[single] => with ' and unquoted " double quotes
)
Other options
JasonDecoder by #ArtisticPhoenix does support unquoted keys and literals, though no '-quoted strings. It's easy to understand or extend however.
YAML (1.2) is a superset of JSON, and most parsers support both unquoted keys or single-quoted strings. See also PHP YAML Parsers
Obviously any JSOL tokenizer/parser in userland is measurably slower than just preprocessing malformed JSON. If you expect no further gotchas from your webservice, go for the regex/quote conversion instead.
One solution would be to build a proxy using NodeJS. NodeJS will handle the faulty JSON just fine and return a clean version:
johan:~ # node
> JSON.stringify(['foo', 'bar']);
'["foo","bar"]'
Maybe write a simple Node script that accepts the JSON data as STDIN and returns the validated JSON to STDOUT. That way you can call it from PHP.
The downside is that your server would need NodeJS. Not sure if that is a problem for you.
If you know that PHP 5.5.+ will parse this JSON gracefully, I would pipe the web service responses trough a proxy script on a PHP5.5+ web server, which sanitizes the responses for lower versions - meaning just echo json_encode(json_decode($response)); That's a stable and reliable approach.
If you make the web service URL configurable trough a config value, it will work for lower versions by accessing the proxy, in higher versions by accessing the web service directly.
A fast solution could be str_replace("'","\"",$string). This depends on many things, but I think you could give it a try.
You could use (and probably modify/extend) a library to build an AST from the supplied JSON and replace the single quotes with double quotes.
https://github.com/Seldaek/jsonlint/blob/master/src/Seld/JsonLint/Lexer.php
Might be a good start.
I'm working with a third party API that receives several parameters which must be encoded like this:
text[]=Hello%20World&text[]=How%20are%20you?&html[]=<p>Just%20fine,%20thank%20you</p>
As you can see this API can accept multiple parameters for text, and also for HTML (not in the sample call).
I have used http_build_query to correctly build a query string for other APIs
$params['text'][] = 'Hello World';
$params['text'][] = 'How are you?';
$params['html'][] = '<p>Just fine, thank you</p>';
$http_query = http_build_query($params);
The problem with this approach is that it will build a query string with the numeric index:
text[0]=Hello%20World&text[1]=How%20are%20you?&html[0]=<p>Just%20fine,%20thank%20you</p>
unfortunately the API I'm working with doesn't like the numeric index and fails.
Is there any php function/class-method that can help me build a query like this quickly?
Thank you
I don't know a standard way to do it (I think there is no such way), but here's an ugly solution:
Since [] is encoded by http_build_query, you may generate string with indices and then replace them.
preg_replace('/(%5B)\d+(%5D=)/i', '$1$2', http_build_query($params));
I very much agree with the answer by RiaD, but you might run into some problems with this code (sorry I can't just make this a comment due to lack of rep).
First off, as far as I know http_build_query returns an urlencode()'d string, which means you won't have [ and ] but instead you'll have %5B and %5D.
Second, PHP's PCRE engine recognizes the '[' character as the beginning of a character class and not just as a simple '[' (PCRE Meta Characters). This may end up replacing ALL digits from your request with '[]'.
You'll more likely want something like this:
preg_replace('/\%5B\d+\%5D/', '%5B%5D', http_build_query($params));
In this case, you'll need to escape the % characters because those also have a special meaning. Provided you have a string with the actual brackets instead of the escapes, try this:
preg_replace('/\[\d+\]/', '[]', $http_query);
There doesn't seem to be a way to do this with http_build_query. Sorry. On the docs page though, someone has this:
function cr_post($a,$b=0,$c=0){
if (!is_array($a)) return false;
foreach ((array)$a as $k=>$v){
if ($c) $k=$b."[]"; elseif (is_int($k)) $k=$b.$k;
if (is_array($v)||is_object($v)) {
$r[]=cr_post($v,$k,1);continue;
}
$r[]=urlencode($k)."=" .urlencode($v);
}
return implode("&",$r);
}
$params['text'][] = 'Hello World';
$params['text'][] = 'How are you?';
$params['html'][] = '<p>Just fine, thank you</p>';
$str = cr_post($params);
echo $str;
I haven't tested it. If it doesn't work then you're going to have to roll your own. Maybe you can publish a github gist so other people can use it!
Try this:
$params['text'][] = 'Hello World';
$params['text'][] = 'How are you?';
$params['html'][] = '<p>Just fine, thank you</p>';
foreach ($params as $key => $value) {
foreach ($value as $key2 => $value2) {
$http_query.= $key . "[]=" . $value2 . "&";
}
}
$http_query = substr($http_query, 0, strlen($http_query)-1); // remove the last '&'
$http_query = str_replace(" ", "%20", $http_query); // manually encode spaces
echo $http_query;
I've a string which looks like this:
[{
text: "key 1",
value: "value 1"
}, {
text: "key 2",
value: "value 2"
}, {
text: "key 3",
value: "value 3"
}]
I'm not sure what kind of notation this is, AFAIK this is generated by a ASP .NET backend. It looks a lot similar to JSON but calling json_decode() on this fails.
Can someone bring me some light on this kind of notation and provide me a efficient way to parse it into a key / value array with PHP?
Any way you can change the output? Quoting the key names seems to allow it to parse normally:
$test = '[{"text":"key 1","value":"value 1"},{"text":"key 2","value":"value 2"},{"text":"key 3","value":"value 3"}]';
var_dump(json_decode($test));
It is JSON-like, but apparently not exactly to the spec. The PHP json_decode function only likes double quoted key names:
// the following strings are valid JavaScript but not valid JSON
// the name and value must be enclosed in double quotes
// single quotes are not valid
$bad_json = "{ 'bar': 'baz' }";
json_decode($bad_json); // null
// the name must be enclosed in double quotes
$bad_json = '{ bar: "baz" }';
json_decode($bad_json); // null
// trailing commas are not allowed
$bad_json = '{ bar: "baz", }';
json_decode($bad_json); // null
That sample is valid YAML, which is a superset of JSON. There seem to be at least 3 PHP libraries for YAML.
If it is in fact YAML, you're better off using a real YAML library, than running it through a regex and throwing it at your JSON library. YAML has support for other features (besides unquoted strings) which, if your ASP.NET backend uses, aren't going to survive the trip.
It looks like javascript syntax (similar to JSON). Regular expressions are the way to go for parsing it. Strip the '[' and ']', then separate on the ','. Then parse each object individually.
It looks like a custom format. Replace the [{ and }] delimiters at the beginning and the end. Then explode on "},{" and you get this:
text:"key 1",value:"value 1"
text:"key 2",value:"value 2"
text:"key 3",value:"value 3"
At that point you can iterate over each element in the array and use preg_match to extract your values.
It looks almost like a sort of array-style data container - text being the index and value being the value.
$string = ....;
$endArray = array()
$string = trim($string,'[]');
$startArray = preg_split('/{.+}/');
// Array of {text:"key 1",value:"value 1"}, this will also skip empty conainers
foreach( $startArray as $arrayItem ) {
$tmpString = trim($arrayItem,'{}'); // $tmp = text:"key 1",value:"value 1"
$tmpArray = explode(',',$tmpString); // $tmpArray = ('text: "key 1"', 'value: "value 1"')
$endArray[substr($tmpArray[0],7,strlen($tmpArray[0])-1)] = substr($tmpArray[1],7,strlen($tmpArray[1])-1);
}
To get your JSON data accepted by json_decode(), you could use the following regular expression:
function json_replacer($match) {
if ($match[0] == '"' || $match[0] == "'") {
return $match;
}
else {
return '"'.$match.'"';
}
}
$json_re = <<<'END'
/ " (?: \\. | [^\\"] )* " # double-quoted string, with escapes
| ' (?: \\. | [^\\'] )* ' # single-quoted string, with escapes
| \b [A-Za-z_] \w* (?=\s*:) # A single word followed by a colon
/x
END;
$json = preg_replace_callback($json_re, 'json_replacer', $json);
Because the matches will never overlap, a word followed by colon inside a string will never match.
I also found a comparison between different JSON implementations for PHP:
http://gggeek.altervista.org/sw/article_20061113.html
I have never used it, but maybe give a look at json_decode.