I am querying a restful web service (clickbank) I am able to send and receive my requests but (embarrassingly enough), I am having trouble parsing the results to make them readable. When I select XML as the return format what I get back is a 97,000 character long string(yay var_dump).... with no spaces in it... and no delimiter (such as ',' or '/', or even '<', or '>'), separating the values. So, I have selected JSON as the return format. I have been able to decode this herculean string using json_decode and I have deciphered that what I am getting back is an array of 100 objects, each object has 30 vars (ala get_object_vars), but some of these vars are themselves arrays of objects. Forgive my ignorance but any ideas on how I can parse this so that it's in the realm of readable? By the way, I am currently trying my hand at PHP (as that is what we use at the shop where I work). I am mildly retarded when it comes to using Eclipse PDT so any suggestions would be welcome....
P.S. I have the following function that has been helpful in determining what the hay is going on but it still doesn't separate things out like I want
function getInfo($datum) {
switch (gettype($datum)) {
case "object":
$GLOBALS['counts']++;
//var_dump($datum);
echo "<hr>";
//$members = get_object_vars($datum);
//getInfo($members);
break;
case "array":
foreach($datum as $v) {
getInfo($v);
}
//var_dump($datum);
break;
default:
echo "<div>$datum</div>";
}
}
This is a bit of a side question here: down at the bottom of my snippet (see the default condition of switch statement), $datum WAS part of an array (before it was passed back into the function at the final depth of recursion here). Is there a way to elaborate that echo statement so that it shows whatever it's key was? I'm trying to word this in the least confusing way possible, but if that value (probably a string) is the value of some index of an associative array, but without me having to specify any of the possible names of the arrays? (think in_array but without the $haystack argument)
Related
Cutting out some of the code on the innermost foreach, I'm trying to change HERE to make it so that it alters the original value. I want to pass a pointer basically and alter it. I was able to kind of do this with the &$ keyword in the foreach but (as the docs state) it results in some buggy behavior and I'm trying to do it the way they, and others on SO suggest. The problem is all the examples I find are for a single foreach, not for nested.
The following code loops properly but when I get to the HERE it doesn't actually alter the original value. Also worth mentioning that $sources could be an array of arrays (by index) or an array of key values. This looping code seems to iterate over both fine though, just not overriding the original value of $sources
fwiw, on top of the &$ I also tried:
$sources[$sourceKey][$rowKey][$cellKey] = $date->format('m/d/Y');
Which $sources[$sourceKey][$rowKey][$cellKey] returns the right value if I print it but it still doesn't overwrite the original array.
function convertDates($sources) {
foreach($sources as $sourceKey => $sourceValue){
foreach ($sourceValue as $rowKey => $rowValue) {
foreach ($rowValue as $cellKey => $cellValue) {
HERE = $date->format('m/d/Y');
}
}
}
}
I never could get this to work correctly since there were two formats this loop could get (JSON encoded object and an array). Making it work for both was much harder than just doing it in JavaScript so instead of modifying on the server I format the data how I want client side and send it up. This formatting is purely presentational and for personal use so if someone were to put in a debugger and change the code to send a different format thats fine and there's no security issues.
So in the end, this code was rewritten in JS and since JS handles arrays and objects using the same pointers the above issue wasn't an issue any longer.
I applied for a job recently and got sent a hackerrank exam with a couple of questions.One of them was a huffman decoding algorithm. There is a similar problem available here which explains the formatting alot better then I can.
The actual task was to take two arguments and return the decoded string.
The first argument is the codes, which is a string array like:
[
"a 00",
"b 101",
"c 0111",
"[newline] 1001"
]
Which is like: single character, two tabs, huffman code.
The newline was specified as being in this format due to the way that hacker rank is set up.
The second argument is a string to decode using the codes. For example:
101000111 = bac
This is my solution:
function decode($codes, $encoded) {
$returnString = '';
$codeArray = array();
foreach($codes as $code) {
sscanf($code, "%s\t\t%s", $letter, $code);
if ($letter == "[newline]")
$letter = "\n";
$codeArray[$code] = $letter;
}
print_r($codeArray);
$numbers = str_split($encoded);
$searchCode = '';
foreach ($numbers as $number) {
$searchCode .= $number;
if (isset($codeArray[$searchCode])) {
$returnString .= $codeArray[$searchCode];
$searchCode = '';
}
}
return $returnString;
}
It passed the two initial tests but there were another five hidden tests which it did not pass and gave no feedback on.
I realize that this solution would not pass if the character was a white space so I tried a less optimal solution that used substr to get the first character and regex matching to get the number but this still passed the first two and failed the hidden five. I tried function in the hacker rank platform with white-space as input and the sandboxed environment could not handle it anyway so I reverted to the above solution as it was more elegant.
I tried the code with special characters, characters from other languages, codes of various sizes and it always returned the desired solution.
I am just frustrated that I could not find the cases that caused this to fail as I found this to be an elegant solution. I would love some feedback both on why this could fail given that there is no white-space and also any feedback on performance increases.
Your basic approach is sound. Since a Huffman code is a prefix code, i.e. no code is a prefix of another, then if your search finds a match, then that must be the code. The second half of your code would work with any proper Huffman code and any message encoded using it.
Some comments. First, the example you provide is not a Huffman code, since the prefixes 010, 0110, 1000, and 11 are not present. Huffman codes are complete, whereas this prefix code is not.
This brings up a second issue, which is that you do not detect this error. You should be checking to see if $searchCode is empty after the end of your loop. If it is not, then the code was not complete, or a code ended in the middle. Either way, the message is corrupt with respect to the provided prefix code. Did the question specify what to do with errors?
The only real issue I would expect with this code is that you did not decode the code description generally enough. Did the question say there were always two tabs, or did you conclude that? Perhaps it was just any amount of space and tabs. Where there other character encodings you neeed to convert like [newline]? I presume you in fact did need to convert them, if one of the examples that worked contained one. Did it? Otherwise, maybe you weren't supposed to convert.
I had the same question for an Coding Challenge. with some modification as the input was a List with (a 111101,b 110010,[newline] 111111 ....)
I took a different approach to solve it,using hashmap but still i too had only 2 sample test case passed.
below is my code:
public static String decode(List<String> codes, String encoded) {
// Write your code here
String result = "";
String buildvalue ="";
HashMap <String,String> codeMap= new HashMap<String,String>();
for(int i=0;i<codes.size();i++){
String S= codes.get(i);
String[] splitedData = S.split("\\s+");
String value=splitedData[0];
String key=(splitedData[1].trim());
codeMap.put(key, value);
}
for(int j=0;j<encoded.length();j++){
buildvalue+=Character.toString(encoded.charAt(j));
if(codeMap.containsKey(buildvalue)){
if(codeMap.get(buildvalue).contains("[newline]")){
result+="\n";
buildvalue="";
}
else{
result+=codeMap.get(buildvalue);
buildvalue="";
}
}
}
return result.toString();
}
}
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.
I'm working with Zend Framework 2's session manager in PHP, and want to unserialize the session data so I can change the way the data is stored. I thought regex was the way to do it, but I can't figure out how to make sure the regex is right for this type of string.
Sample input:
__ZF|a:2:{s:20:"_REQUEST_ACCESS_TIME";d:1099999999.9999999999999999999999;s:6:"_VALID";a:1:{s:25:"Zend\Session\Validator\Id";s:26:"xxxxxxxxxxxxxxxxxxxxxxxxxx";}}initialized|C:23:"Zend\Stdlib\ArrayObject":403:{a:4:{s:7:"storage";a:3:{s:4:"init";i:1;s:10:"remoteAddr";s:13:"127.000.00.01";s:13:"httpUserAgent";s:114:"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";}s:4:"flag";i:2;s:13:"iteratorClass";s:13:"ArrayIterator";s:19:"protectedProperties";a:4:{i:0;s:7:"storage";i:1;s:4:"flag";i:2;s:13:"iteratorClass";i:3;s:19:"protectedProperties";}}}
Expected output:
'__ZF|a:2:{s:20:"_REQUEST_ACCESS_TIME";d:1099999999.9999999999999999999999;s:6:"_VALID";a:1:{s:25:"Zend\Session\Validator\Id";s:26:"xxxxxxxxxxxxxxxxxxxxxxxxxx";}}'
'initialized|C:23:"Zend\Stdlib\ArrayObject":403:{a:4:{s:7:"storage";a:3:{s:4:"init";i:1;s:10:"remoteAddr";s:13:"127.000.00.01";s:13:"httpUserAgent";s:114:"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";}s:4:"flag";i:2;s:13:"iteratorClass";s:13:"ArrayIterator";s:19:"protectedProperties";a:4:{i:0;s:7:"storage";i:1;s:4:"flag";i:2;s:13:"iteratorClass";i:3;s:19:"protectedProperties";}}}'
What I tried:
$pattern = '/\w+\|.*?}}+/'; // this works for the sample input, but may be too general and certainly won't work for serialized data without a nested array
$pattern = '/\w+\|(a:\d+:{.*?}|o:\d+:\"[a-z0-9_]+\":\d+:{.*?})/'; // doesn't capture the `initialized` data
Where I am stuck:
Put generally, I can't figure out the best way to split apart the __ZF data from the initialized data (especially when there are other non-Zend variables in the session). Specifically, I can't figure out what regex to use to get serialized data.
I tried to put an example on RegexPlanet, but couldn't figure out the interface, and it only seemed to produce bizarre results. If it helps, I'm fairly sure ZF PHP produces its serialized session data like this:
$text = "";
foreach ($_SESSION as $key => $value) {
$text .= $key . "|" . serialize($value);
}
...but I haven't found the source code for that.
I found out about ini_set('session.serialize_handler', 'php_serialize'); It changes the serialization to use PHP's regular serialize method instead of the alternate, which solves the problem. – Miryafa
After hours of debugging, I found an error in one of my scripts. For saving different event types in a database, I have an array of unique data for each event that can be used to identify the event.
So I basically have some code like
$key = md5(json_encode($data));
to generate a unique key for each event.
Now, in some cases, a value in the $data array is an integer, sometimes a string (depending on where it comes from - database or URL). That causes the outputs of json_encode() to be different from each other, though - once including quotes, once not.
Does anybody know a way to "unify" the variable types in the $data array? That would probably mean converting all strings that only contain an integer value to integer. Anything else I have to take care of when using json_encode()?
array_walk_recursive combined with a function you have written to the effect of maybe_intval which performs the conversion you talk about on a single element.
EDIT: having read the documentation for array_walk_recursive more closely you'll actually want to write your own recursive function
function to_json($obj){
if(is_object($obj))
$obj=(array)$obj;
if(is_array($obj))
return array_map('to_json',$obj);
return "$obj"; // or return is_int($obj)?intval($obj):$obj;
}