Binding values to a JSON string using PHP - php

Using PHP, I'd like to bind a value to a JSON string similar to how it is done when preparing an SQL statement for a database using a question mark. For example, I would like do something like the following:
$v1 = 'v1';
$k2 = 'k2';
$result = json_bind('[{"k1": ?}, {?: "v2"}]', $v1, $k2);
echo $result; // [{"k1": "v1"}, {"k2": "v2"}]
I don't want to just do a pure string replace as this technique doesn't escape/quote the values properly and it can't format values like arrays and objects properly.
I don't want to just create an array (or an object) first, assign my params, and use json_encode because this gets messy since PHP's syntax differs from JSON's syntax and I need something more dynamic because I may not always know the structure of the JSON.
Is there already a library or function that can do this very thing?

Is there already a library or function that can do this very thing?
No.

It's sort of doable with a simple regex "tokenizer" - by skipping strings mostly.
#-- Replace `?` placeholders
function json_bind($template, ...$vars) {
return preg_replace_callback(
'/
[{}[\],:] \K | # meta chars
(true|false|null) \K | # literals
[-+\d.e]+ \K | # numbers
"([^"\\\\]+|\\\\.)*" \K | # strings
([?]) # placeholder (do not skip)
/x',
function ($m) use (& $vars) {
if ($m[0] == "?") {
return json_encode(array_shift($vars));
}
},
$template
);
}
While that's not a very complete/clean regex, it should skip over most standard JSON structures and most strings (see Regex to validate JSON for better regexps). Which is how you can find literal ? placeholders.
Notably that doesn't take care of semantically invalid templates, like array params for JSON keys e.g.

How can you not know the JSON structure? What than is the use of passing values to a function in order to bind values to a string, if you can not distinguish a question mark being a key or a value?
In a sence you are saying I do know what I want to bind and I pass it in an arbitrary way to a function, although I have no clue as to the structure of the source JSON string. Thus I have no clue as to the outcome being correct or not.
Why would anyone want to have such a thing?
You simply have to go with the answer of #Bart Friederichs. This is the only proper answer to your question.

Related

keep adding up code from database

# Check arrary not empty
if (!empty($results)) {
$this->code($results);
// got the mail code from database
// which is PG-000001
// how do i add , like something PG-000001 ++
}
this will return a result from database , my intention is to keep adding up the code that return from my database and the update back to the database.
now it was return PG-000001, how do i make it add up and be like PG-000002 and then update it and next time it will be PG-000002 and up to 000003 and so on.
how do i add up the text PG-000001?
If all of your codes look like this, then your really shouldn’t store them that way. It appears that the PG- at the beginning is just a prefix. If you store the actual value as an integer, you can increment as much as you like.
Anyway, the solution to your question is that you will need to
split the string
increment the second part
zero-pad the second part
combine again
Here is a little test script:
$test='PG-000001';
$pattern='/(.*-)(\d+)/';
preg_match($pattern,$test,$matches);
list(,$prefix,$value)=$matches;
$value=sprintf('%06d',$value+1);
$test="$prefix$value";
print $test;
Translation:
/(.*-)(\d+)/ is the pattern that will split the string into the prefix & numeral
preg_match applies the pattern and returns the result into the array $matches.
$matches has the original string, and then the two matches
list() copies elements of the array into variables. The leading comma skips the first element
sprintf formats the data. In this case, the code 0-pads to 6 digits
the double-quoted string is a simple way of recombining your data.

PHP preg_match template array as a second argument not working

I found this neat code from: https://www.webmasterworld.com/php/3444822.htm
First example seems to work well:
$firstname = "Eric";
$lastname = "Johnsson";
echo preg_replace("/\{([^\{]{1,100}?)\}/e", "$$1", "{lastname}, {firstname}");
But when I try to use second array version, it gives me index and other errors what ever combinations I try:
$values = array('firstname'=>'Eric', 'lastname'=>'Johnsson');
echo preg_replace("/\{([^\{]{1,100}?)\}/e", "$values[$1]", "{lastname}, {firstname}");
In PHP 5.5x it "should" work. PHP 7.x -> needs to have second argument a function, not accepting -e argument on regex.
Does anyone know working solution to second version? I rather not use export function to extract variables to the working scope.
You need to use preg_replace_callback as in the code below:
$values = array('firstname'=>'Eric', 'lastname'=>'Johnsson');
echo preg_replace_callback("/{([^{}]*)}/", function($m) use ($values) {
return !empty($values[$m[1]]) ? $values[$m[1]] : $m[0];
}, "{lastname}, {firstname} {somestring}");
See the PHP demo
Note that to pass the $values to the anonymous callback function, you need to pass it within use argument. With !empty($values[$m[1]]) you can check if your array contains the necessary key-value, and if yes, replace with it, and if not, just restore the match with the current match value, $m[0].
Note you do not need to escape { and } in this pattern, and you may just use {([^{}]*)} to match any number of chars other than { and } between { and }. If you are only interested in the substrings containing word chars, a {(\w+)} pattern could be more suitable.

PHP - Exploding on character(s) that can NEVER be user-defined... How?

Ok, am trying to find a character or group of characters, or something that can be used that I can explode from, since the text is user-defined, I need to be able to explode from a value that I have that can never be within the text.
How can I do this?
An example of what I'm trying to do...
$value = 'text|0||#fd9||right';
Ok,
text is something that should never change in here.
0, again not changeable
#fd9 is a user-defined string that can be anything that the user inputs...
and right sets the orientation (either left or right).
So, the problem I'm facing is this: How to explode("||", $value) so that if there is a || within the user-defined part... Example:
$value = 'text|0||Just some || text in here||right';
So, if the user places the || in the user-defined part of the string, than this messes this up. How to do this no matter what the user inputs into the string? So that it should return the following array:
array('text|0', 'Just some || text in here', 'right');
Should I be using different character(s) to explode from? If so, what can I use that the user will not be able to input into the string, or how can I check for this, and fix it? I probably shouldn't be using || in this case, but what can I use to fix this?
Also, the value will be coming from a string at first, and than from the database afterwards (once saved).
Any Ideas?
The problem of how to represent arbitrary data types as strings always runs up against exactly the problem you're describing and it has been solved in many ways already. This process is called serialization and there are many serialization formats, anything from PHP's native serialize to JSON to XML. All these formats specify how to present complex data structures as strings, including escaping rules for how to use characters that have a special meaning in the serialization format in the serialized values themselves.
From the comments:
Ok, well, basically, it's straight forward. I already outlined 13 of the other parameters and how they work in Dream Portal located here: http://dream-portal.net/topic_122.0.html so, you can see how they fit in. I'm working on a fieldset parameter that basically uses all of these parameters and than some to include multiple parameters into 1. Anyways, hope that link helps you, for an idea of what an XML file looks like for a module: http://dream-portal.net/topic_98.0.html look at the info.xml section, pay attention to the <param> tag in there, at the bottom, 2 of them.
It seems to me that a more sensible use of XML would make this a lot easier. I haven't read the whole thing in detail, but an XML element like
<param name="test_param" type="select">0:opt1;opt2;opt3</param>
would make much more sense written as
<select name="test_param">
<option default>opt1</option>
<option>opt2</option>
<option>opt3</option>
</select>
Each unique configuration option can have its own unique element namespace with custom sub-elements depending on the type of parameter you need to represent. Then there's no need to invent a custom mini-format for each possible parameter. It also allows you to create a formal XML schema (whether this will do you any good or not is a different topic, but at least you're using XML as it was meant to be used).
You can encode any user input to base64 and then use it with explode or however you wish.
print base64_encode("abcdefghijklmnopqrstuvwxyz1234567890`~!##$%^&*()_+-=[];,./?>:}{<");
serialized arrays are also not a bad idea at all. it's probably better than using a comma separated string and explode. Drupal makes good use of serialized arrays.
take a look at the PHP manual on how to use it:
serialize()
unserialize()
EDIT: New Solution
Is it a guarantee that text doesn't contain || itself?
If it doesn't, you can use substr() in combination with strpos() and strrpos() instead of explode
Here's what I usually do to get around this problem.
1) capture user's text and save it in a var $user_text;
2) run an str_replace() on $user_text to replace the characters you want to split by:
//replace with some random string the user would hopefully never enter
$modified = str_replace('||','{%^#',$user_text);
3) now you can safely explode your text using ||
4) now run an str_replace on each part of the explode, to set it back to the original user entered text
foreach($parts as &$part) {
$part = str_replace('{%^#','||',$part);
}

Getting array param out of query string with PHP

(NOTE: This is a follow up to a previous question, How to pass an array within a query string?, where I asked about standard methods for passing arrays within query strings.)
I now have some PHP code that needs to consume the said query string- What kind of query string array formats does PHP recognize, and do I have to do anything special to retrieve the array?
The following doesn't seem to work:
Query string:
?formparts=[a,b,c]
PHP:
$myarray = $_GET["formparts"];
echo gettype($myarray)
result:
string
Your query string should rather look like this:
?formparts[]=a&formparts[]=b&formparts[]=c
If you're dealing with a query string, you are looking at the $_GET variable. This will contain everything after the ? in your previous question.
So what you will have to do is pretty much the opposite of the other question.
$products = array();
// ... Add some checking of $_GET to make sure it is sane
....
// then assign..
$products = explode(',', $_GET['pname']);
and so on for each variable. I must give you a full warning here, you MUST check what comes through the $_GET variable to make sure it is sane. Otherwise you risk having your site compromised.

APACHE mod_rewrite change variable name in query string

I'm trying to change a variable name in a query string, so it's usable by my PHP code.
The query gets posts from an external system, so I can't control that they are posting a variable name with a space in it. And that makes it impossible for me to use the PHP $_GET function.
I need to change variable%20name to ?new1
And I need to change variable2 to new2
There are many variables passed in the query, but only these two need to be changed. The rest can stay the same or even disappear.
So ?variable%20name=abc&variable2=xyz
Needs to end up as ?new1=abc&new2=xyz
Also, they may not be in this order and there may be more variables
So ?variable%20name=abc&blah=123&blah2=456&variable2=xyz
Could end up as ?new1=abc&new2=xyz
OR as ?new1=abc&blah=123&blah2=456&new2=xyz
Either way would be fine!
Please give me the mod_rewrite rule that will fix this.
Thank you in advance!
Parsing the query string with mod_rewrite is a bit of a pain, has to be done with RewriteCond and using %n replacements in a subsequent RewriteRule, probably easier to manually break up the original query string in PHP.
The full query string can be found (within PHP) in $_SERVER['QUERY_STRING'].
You can split it up using preg_split() or explode(), first on &, then on =, to get key/value pairs.
Using custom%20cbid=123&blahblahblah&name=example as an example.
$params = array();
foreach (explode("&", $_SERVER['QUERY_STRING']) as $cKeyValue) {
list ($cKey, $cValue) = explode('=', $cKeyValue, 2);
$params[urldecode($cKey)] = urldecode($cValue);
}
// Would result in:
$params = array('custom cbid' => 123,
'blahblahblah' => NULL,
'name' => example);

Categories