PHP Cookies - Stores 2 pieces of data in one cookie - php

I have 2 pieces of data related to the same topic being country an country code.
eg: Australia and AU
Is there a preferred way to store 2 pieces of data in the one cookie?
Or Better to just use 2 cookies.
Sorry if this is a silly questions... Just interested in other peoples opinions.
thx

If it were me I would just append the data together using a specific glue, then explode the string when I wanted to separate the values again.
$cookeString = $country . '+' . $countryCode;
list($country, $countryCode) = explode('+', $cookieString);
But in all honesty it doesn't make sense to store country and country code, just store country code and look up country data using country code as a key.

Why not use javascript and create a json object ?
var cc = {
australia: 'au',
India : 'In'
}
You can use as cc.India
I know, you asked about cookies, but I needed to store country codes, and I did this way. Its fast and easy.

You can do it a number of ways, either multiple cookies, or storing an Object like JSON, or you could just simply put a string delimited by something like :: for example and user php's eplode function. All in all its a matter of preference and dependent upon what your doing. If you use a JSON object you could easily switch back and forth between the object and an array as well through the use of json_encode and json_decode. Again its all about where your comfort level is. All in all though your looking at working with an array of data in the end if you really want to keep it in a single cookie.
Example:
<?php
//set the cookie
$cookieData = json_encode(array("value_one", "value_two"));
setcookie("MyCookie", $cookieData , time()+3600);
//read the cookie
$cookieInfo = json_decode($_COOKIE['MyCookie']);
echo $cookieInfo[0]."<br>";
echo $cookieInfo[1]."<br>";
//or
for($i = 0; $i < count($cookieInfo); $i++)
{
echo $cookieInfo[$i]."<br>";
}
You can make this concept fairly large, but bare in mind cookies are easily manipulated client side so sanitize your cookie variables before running them through script that can be injected and broken for other needs, example checking a database to see if a use is valid via cookie information.
Another thing to remember is some browsers have a cookie size, you where the max size of a cookie is 4kb only.
Also you can get a little more fancy with the logic of using JSON and Arrays, they are tricky at first if your not familiar with them but once you start using them and understand them, you will find they are your best friends.

You can also set array cookies by using array notation in the cookie name.
PHP Code -
// set the cookies
setcookie("cookie[one]", "cookie1");
setcookie("cookie[two]", "cookie2");
setcookie("cookie[three]", "cookie3");
// after the page reloads, print them out
if (isset($_COOKIE['cookie'])) {
foreach ($_COOKIE['cookie'] as $name => $value) {
$name = htmlspecialchars($name);
$value = htmlspecialchars($value);
echo "$name : $value <br />";
}
}
Output:
one : cookie1
two : cookie2
three : cookie3

Related

I need to add fields to a JSON string in PHP, but I'm having problems

So... I need to save a large-ish amount of data from a platform with an excruciatingly limited amount of memory.
Because of this, I'm basically storing the data on my webserver, using a php script to just write JSON to a flat file, because I'm lazy af.
I could go to the trouble of having it store the data in my mysql server, but frankly the flat file thing should have been trivial, but I've run up against a problem. There are several quick and dirty workarounds that would fix it, but I've been trying to fix it the "right" way (I know, I know, the right way would be to just store the data in mysql, but I actually need to be able to take the json file this produces and send it back to the platform that needs the data (In a ridiculously roundabout fashion), so it made sense to just have the php save it as a flat file in the first place. And It's already working, aside from this one issue, so I hate to reimpliment.
See... Because of the low memory on the platform I'm sending the json to my server from... I'm sending things one field at a time. Each call to the php script is only setting ONE field.
So basically what I'm doing is loading the file from disk if it exists, and running it through json_decode to get my storage object, and then the php file gets a key argument and a value argument, and if the key is something like "object1,object2", it explodes that, gets the length of the resulting array, and then stores the value in $data->$key[0]->$key[1].
Then it's saved back to disk with fwrite($file, json_encode($data));
This is all working perfectly. Except when $value is a simple string. If it's an array, it works perfectly. If it's a number, it works fine. If it's a string, I get null from json_decode. I have tried every way I can think of to force quotes on to the ends of the $value variable in the hopes of getting json_decode to recognize it. Nothing works.
I've tried setting $data->$key[0]->$key[1] = $value in cases where value is a string, and not an array or number. No dice, php just complains that I'm trying to set an object that doesn't exist. It's fine if I'm using the output of json_decode to set the field, but it simply will not accept a string on its own.
So I have no idea.
Does anyone know how I can either get json_decode to not choke on a string that's just a string, or add a new field to an existing php object without using the output of json_decode?
I'm sure there's something obvious I'm missing. It should be clear I'm no php guru. I've never really used arrays and objects in php, so their vagaries are not something I'm familiar with.
Solutions I'm already aware of, but would prefer to avoid, are: I could have the platform that's sending the post requests wrap single, non-numeric values with square braces, creating a single item array, but this shouldn't be necessary, as far as I'm aware, so doing this bothers me (And ends up costing me something like half a kilobyte of storage that shouldn't need to be used).
I could also change some of my json from objects to arrays in order to get php to let me add items more readily, but it seems like there should be a solution that doesn't require that, so I'd really prefer not to...
I skim through your post.
And I know this works for StdClass :
$yourClass->newField = $string;
Is this what you wanted ?
OK so... ultimately, as succinctly as possible, the problem was this:
Assuming we have this JSON in $data:
{
"key1":
{
"key2":["somedata","someotherdata"]
}
}
And we want it to be:
{
"key1":
{
"key2":["somedata","someotherdata"],
"key3":"key3data"
}
}
The php script has received "key=key1,key3&value=key3data" as its post data, and is initialized thusly:
$key = $_POST["key"];
$key = explode($key,",");
$value = $_POST["value"];
...which provides us with an array ($key) representing the nested json key we want to set as a field, and a variable ($value) holding the value we want to set it to.
Approach #1:
$data->$key[0]->$key[1] = json_decode($value);
...fails. It creates this JSON when we re-encode $data:
{
"key1":
{
"key2":["somedata","someotherdata"],
"key3":null
}
}
Approach #2:
$data->$key[0]->$key[1] = $value;
...also fails. It fails to insert the field into $data at all.
But then I realized... the problem with #2 is that it won't let me set the nonexistent field, and the problem with approach #1 is that it sets the field wrong.
So all I have to do is brute force it thusly:
$data->$key[0]->$key[1] = json_decode($value);
if (json_decode($value) == NULL)
{
$data->$key[0]->$key[1] = $value;
}
This works! Since Approach #1 has created the field (Albeit with the incorrect value), PHP now allows me to set the value of that field without complaint.
It's a very brute force sort of means of fixing the problem, and I'm sure there are better ones, if I understood PHP objects better. But this works, so at least I have my code working.

What's a simple symmetric way to encrypt a string and pass through a url in php?

As the question states, I need a way to encrypt a string (i.e. 'x=27&y=3&z=123456' into 'hUIgBG5664y65H2UIB') so that it can be passed via an html image source, like so:
<img src="returnpicture.php?stuff=hUIgBG5664y65H2UIB"/>
returnpicture.php will decrypt that back into 'x=27&y=3&z=123456' and parse it into three variables which will be used to pick an image and return it.
Problem is, everywhere I look, all I can find is stuff about hashing and encrypting super-sensitive information like credit cards and passwords. This info is not sensitive at all, I just don't want users to be able to tamper with it. Therefore, it shouldn't be excessively long. Also, the encryption (I'm guessing) must be alphanumeric, so as not to mess up the url with & or =. I'm doing this in php.
It's for a sort of game. The user shouldn't be able to mess with the variables, 'cause they'll see things they shouldn't yet.
For general understanding
When you include certain key-value pairs in your request url, PHP will load these values (accordingly) into the $_GET superglobal.
?x=12&y=13
Will result in
$_GET['x'] // contains 12
$_GET['y'] // contains 13
What you seem to be trying to do is to supply multiple key-value pairs within a key-value pair:
?stuff={more-key-value-pairs}
Simply be aware that PHP will not interpret key-value pairs in $_GET['stuff'].
Encoding/Decoding
Note: This is one possible solution out of many. Find the one that suits you most and apply it.
You can use base64_encode() to encode it, and base64_decode() to decode it.
Example:
echo '<img src="returnpicture.php?stuff=' . rawurlencode( base64_encode('x=27&y=3&z=123456') ) . '" />';
Usage of rawurlencode() assures proper url safe encoding of the base64-encoded string.
In your returnpicture.php you can use:
$decodedString = base64_decode( $_GET['stuff'] );
to get back your original string.
However, if you actually plan on sending a get-request like string (with variable assignments, such as ?x=12&y=13 and so on, then you need to apply further techniques to get that string parsed.
See this question for details on how it can be done
You could use a simple cipher, like a rolling XOR hash. This is very easy to implement, but enough of a nuisance to crack that people probably won't bother if the only benefit is something trivial, like the ability to get your server to serve images in non-standard sizes.
function scramble(key, text) {
return encodeURIComponent(text.replace(/[^\0]/g, function(x, i) {
var code = x.charCodeAt(0) ^ key.charCodeAt(i % key.length);
return String.fromCharCode(code);
}));
}
function descramble(key, text) {
return decodeURIComponent(text).replace(/[^\0]/g, function(x, i) {
var code = x.charCodeAt(0) ^ key.charCodeAt(i % key.length);
return String.fromCharCode(code);
});
}
If your key is "secretcode" and your text is "x=27&y=3&z=123456", then scramble(key, text) returns "%0BXQEC%0D%5E%5CB%1FNTQAQAU".
"Descrambling" that result with the same key gives the original text, "x=27&y=3&z=123456".
Note that you'd probably want to do this on the PHP side of things, the JavaScript code is just here as an example.
http://jsfiddle.net/m92rc/
I suggest that you can share information between your pages with $_SESSION vars, but, it only works if two pages are in same context server.
Approach 1. base64 encode
<img src="returnpicture.php?stuff=<?php echo base64_encode('x=27&y=3&z=123456'); ?>"/>
And get this as:
$data = base64_decode($_GET['stuff']);
Approach 2. $_SESSION variables
You should combine $_GET with $_POST without expose sensible information like:
$postfix = uniqid(); // Generate an UNIQUE id
$_SESSION['sensible_var1_'.$postfix] = "value";
$_SESSION['sensible_var2_'.$postfix] = "value";
$_SESSION['sensible_var3_'.$postfix] = "value";
And you can pass this information only with:
<img src="returnpicture.php?stuff=<?php echo $postfix; ?>"/>
And in your returnpicture.php file, you can retrive information as:
$sensible_var1 = $_SESSION['sensible_var1_'.$_GET['stuff']];
$sensible_var2 = $_SESSION['sensible_var2_'.$_GET['stuff']];
$sensible_var3 = $_SESSION['sensible_var3_'.$_GET['stuff']];

Using explode with setcookie to set one cookie with multiple name and values

I really not getting how to do this
From PHP Manual
Cookies names can be set as array names and will be available to your
PHP scripts as arrays but separate cookies are stored on the user's
system.
This is okay to me and I got and could use like below
setcookie("cookie[three]", "cookiethree");
setcookie("cookie[two]", "cookietwo");
But this method will create multiple cookies and that is I don't want
PHP manual also says
Consider explode() to set one cookie with multiple names and
values.
But I did not get how to use explode to set one cookie with multiple names and values?
Please someone explain this.
But not getting this
Cookies are nothing else than a dumb key/value storage system. It's as simple as that.
It happens that PHP offers a nifty feature on top of that: cookies whose names contain square brackets in the described format will be combined into a single array variable when reading cookies back from PHP. But that's the only exception, it doesn't affect the way cookies work and, as you've said, it's a feature you don't need.
Said that, you only need to think of the cookie value as a whiteboard where you can put anything you want, as long as it's text. And there're many PHP functions that allow you to convert exotic stuff like arrays into plain text:
serialize()
json_encode()
implode()
...
Use your imagination and you're done ;-)
Update: A little remarkā€”I've mentioned serialize() for completeness, but it's probably not worth the effort since it'd be very complicate to ensure you don't open the door to code injection.
Use Serialize and Unserialize
Ex :
$ckArr= array();
$ckArr['abc'] = "abc";
$ckArr['xyz'] = "xyz";
$ckArr['pqr'] = "pqr";
$ckStr= serialize($ckArr);
setcookie("mycookie", $ckStr, $time, $servername);
And you can unserialised it using :
$cookieContent = unserialize($_COOKIE['mycookie']);
print_r($cookieContent);
You can set a cookie like this:
setcookie("cookiename", "value1;value2;value3;value4");
and then use explode like so:
$a = explode(';', $_COOKIE['cookiename']);
Then you will get an array of values from a single cookie.
It is also saying you should not do this... in the following sentence of the doc.
setcookie("cookiename", serialize( array("value1", "value2", "value3") );
// next request
$a = unserialize($_COOKIE['cookiename']);
because that is unsafe as users can modify their cookies to non-array values.

Consolidating multiple GET parameters into a single value

Im not really sure what im looking for but currently in my system i send a long url like this:
$name=1&option=2&field=4....
And its quite long. So if i have a list of values like:
name
option
field
can i put them into a string in which i can break at certain points eg by a slash or whatever.
And then encode the string so its completely random like, so i only have one field to send:
&data=JKHFGDKGLKJHFKDJHFKJDHFKHDF
Then finally i can decode the other side and break apart.
Is there a pre-built function to do this?
WHAT IT IS:
im sending data to paypal, but i have a few custom variables i wish to send, now for some reason my IPN isnt geting them, not sure why, but if i add one called custom it get to the IPN fine. So i thought if i just send one called custom in a random format and then decode?
You could simply Base64-encode your data.
$a = array('name' => '1', 'option' => '2', 'field' => '4');
$temp = json_encode($a); // convert array to string
$data = base64_encode($temp); // encode string
output:
"eyJuYW1lIjoiMSIsIm9wdGlvbiI6IjIiLCJmaWVsZCI6IjQifQ=="
To send this in an URL, you must encode it once more (like you must encode all data you would send in a URL)
$url = $url . "&data=" . urlencode($data)
The intermediary step through JSON ensures your data will kep its structure and will be easily decodeable on the receiving side.
On the downside: Your URL will be longer.
Use base64_encode and then base64_decode, this will solve your problem.
If you don't know what you are looking for we can't imagine that lol.
Anyway If i got you, you can do this, considering you have built your string:
$string ="$name=1&option=2&field=4";
You could pass it as a single param with:
$data = url_encode($string);
Other than url_encode you can use base64_encode
As the commenter (Bobby) says - consider using POST when you want to send larger sets of data and prevent your URL from becoming unmanageably long or ugly.
GET variables are handy for providing the user with a page they can bookmark directly which is desirable in some cases, such as on a search page with a query string and/or filters already filled in, so that the user can return to a search and check for new results periodically without having to reset all of their choices.
POST variables are better if you don't need that sort of functionality, you don't need to encode/decode them for URLs and they can't be bookmarked directly (which is also desirable in many cases).
To answer your original question though, if you really, really had to send the variable(s) on the URL and you wanted to just send one apparently random string, I suggest writing a couple of encode/decode functions of your own (since I assume the object of the excercise is not to encrypt it against tampering, just to make your URLs friendlier). This will be all the easier if there are restrictions to what the variables can be, and more difficult if they can be absolutely anything.
For example - if you have the following vars and possible settings:
var1 (apple, banana, orange)
var2 (car, motorbike, bicycle)
var3 (red, yellow, green)
Normally, you'd make a URL like:
http://www.mysite.com/page.php?var1=banana&var2=car&var3=green
If you assign the variables to numbers (for example) so that var1, var2 and var3 would be 1, 2 or 3 - then you could send over a URL like:
http://www.mysite.com/page.php?vars=213
Break it down at the other end into single numbers and convert those back into 'banana', 'car', and 'green'.
But seriously.... I'd look at POST first unless there is very specific reason why you would use this sort of approach - i've used it before for shortening a URL to make it more sharable on social media and forums.

Multiple Variables into 1 in a URL

I am looking to have a list of arguments passed across in an a URL.
$url['key1']=1;
$url['key2']=2;
$url['key3']=3;
$url['key4']=4;
$url['key5']=5;
$url['key6']=6;
$url['key7']=7;
Please Note I am trying to pass this in the URL in 1 GET variable. I know this would be better done by ?key1=1&key2=2&key3=3...etc but for reasons that are too complicated to try and explain they can't be in this format.
Any suggestions how I can convert this array into something that can be passed as 1 get var in a URL string?
Thanks in advance.
You can use json_encode() or serialize()
$myUrl = 'http://www.example.com/?myKey=' . urlencode(json_encode($url));
or
$myUrl = 'http://www.example.com/?myKey=' . urlencode(serialize($url));
Using json_encode will usually give you a shorter string, but very old PHP version might not have the json_decode function available to decode it again.
The final way would be to create your own custom encoding... it could be as simple a pipe-separated values: key1|1|key2|2|key3|3
This would give you the best option for a short URL, but is the most work.
Try http_build_query:
$url['key1']=1;
$url['key2']=2;
$url['key3']=3;
$url['key4']=4;
$url['key5']=5;
$url['key6']=6;
$url['key7']=7;
echo http_build_query($url);
//echos key1=1&key2=2&key3=3&key...
What it does is converting an array into a query string using the keys and automatically takes care of url-encoding.
EDIT:
Just read your additional requirement that it should be just one variable. So nevermind this answer.
If your problem was the proper encoding though you might want to give this another try.
Hope that helps.
The recommendation to use serialize() is fine. If space is an issue, then use a combination of bzcompress() and serialize().
However, there's a security considering that hasn't been brought up, and that's that the end user (who can see and edit this url) could manipulate the data within it. You may think it's difficult, but most of the PHP-attacking worms in the wild do this to some degree or another.
If letting the user directly manipulate any of the keys or values (or replacing it with an integer, or an object, or anything else), then you should protect your script (and your users) from this attack.
A simple solution is to simply use a shared secret. It can be anything; just so long as it's unique and truly secret (perhaps you should randomly generate it at install-time). Let's say you have in your config file something like this:
define('SECRET', 'unoqetbioqtnioqrntbioqt');
Then, you can digitally sign the serialized data created with: $s=serialize($m) using $k=sha1($s.SECRET) and make the url value $k.$s
Then, before you unserialize() do this:
$v=substr($input,0,40);
$s=substr($input,40);
if ($v != sha1($s.SECRET)) { die("invalid input"); }
$m=unserialize($s);
This way, you know that $m is the same as the original value that you serialized.
If you like, you can use the following drop-in replacements:
define('SECRET','buh9tnb1094tib014'); // make sure you pick something else
function secureserialize($o) {
$s=serialize($o);
return sha1($s.SECRET).$s;
}
function secureunserialize($i) {
$v=substr($i,0,40);$s=substr($i,40);
if ($v!=sha1($s.SECRET)){die("invalid input");}
return unserialize($s);
}
You could serialize them as key-value pairs when constructing the URL, putting the resultant serialized value in a single $_GET variable (e.g. data=sfsdfasdf98sdfasdf), then unserialize the $_GET["data"] variable. You'll need to use urlencode to make sure the resultant serialized values are URL-safe. Make sure you watch out for maximum URL lengths - 2083 characters in IE.
However, unless you really can't use key-value pairs in URLs (per your question), key1=foo&key2=bar... is definitely the way to go.
If you don't mind dropping the key names, you can use
http://example.com?url[]=1&url[]=2&url[]=3
EDIT Keeping the key names:
http://example.com?values[]=1&values[]=2&values[]=3&keys[]=1&keys[]=2&keys[]=3
Then in your PHP script:
$url = array_combine($_GET['keys'], $_GET['values']);
Could you solve your problem by saving the data as a HTML cookie? That way you don't have to modify the URL at all.
If you know the values in advance, you can set them from the server side when you send the user the page with your target link on it.
If you won't know the values until the user fills out a form it can still be done using JavascriptL When the user clicks the form submit you can set multiple cookies by making multiple javascript calls like:
document.cookie = 'key1=test; expires=Mon, 7 Sept 2009 23:47:11 UTC; path=/'
The security model might give you some trouble if you are trying to pass this data from one domain to another though.

Categories