I have an IP phone that through 2 action urls makes a get request to my web server.
action urls:
http://192.168.25.126/action.php?ID=$call_id&remote=$display_remote
http://192.168.25.126/action.php?ID=$call_id&extension=$active_user
192.168.25.126 is the web server
action.php is printing to a log file the request
$call_id is a unique ID that the phone is giving to the current session
$remote is the caller's number
$extension is the ip phone extension number
on the server side I have the action.php that prints in a log file the requests through this simple line
<?php
file_put_contents("/tmp/post.log",print_r($_GET,true), FILE_APPEND));
?>
checking the log I can view the expected request
tail -f /tmp/post.log
Array
(
[ID] => 9
[remote] => +39123456789
)
Array
(
[ID] => 9
[extension] => 235
)
How can I merge in tmp.log the arreys with same ID like this?
Array
(
[ID] => 9
[remote] => +39123456789
[extension] => 235
)
pay attention that the first arrey is generated on the ringing event and the second arrey is generated when I pickup the phone(or better to say when a call in enstablished)so in a second moment
I cannot do this with only one action url like this
http://192.168.25.126/action.php?ID=$call_id&remote=$display_remote&extension=$active_user
due a limitation of my ip phone so I have to merge the 2 arreys. and if possible I would like,but this is not really necessary, that the log is printed only if the first arrey with same ID exist(so the log will appears only if an incoming call is answered and not when I make a call).
I'm a senior IT not a php coder so just want a suggestion to write the loop.. many thanks
From what I'm understanding this should do what you need - expecting IDs to be unique.
<?php
// get data from log
$fileData = file_get_contents("/tmp/post.log");
$data = json_decode($fileData, true); // make an array out of the json
// $data will now be something like this:
# $data = [["ID" => 9,"remote" => "+39123456789"],["ID" => 10,"remote" => "+41123456789"]];
// mocking input data
# $_GET = ['ID' => 10, 'otherparam' => 'bar'];
$key = array_search($_GET['ID'], array_column($data, 'ID')); // search for pre-saved data
if($key) { // an item with $ID was found -> merge new data
$item = array_merge($data[$key], $_GET);
$data[$key] = $item; // overwrite existing item with this ID
} else {
$item = $_GET; // create a new item, since we haven't found one
$data[] = $item; // append to data
}
file_put_contents("/tmp/post.log",json_encode($data,true))); // don't append, write the whole dataset
If the IDs are not unique, we could just grab the last added one (via end(), check if IDs match and merge there:
end($data); // set pointer to the end
$key = key($data); // get the key of the last element
if($data[$key]['ID']==$_GET['ID']) {
$item = array_merge($data[$key], $_GET); // merge old and new data
$data[$key] = $item; // overwrite item
}
EDIT:
If you only need the last call, we don't need to re-save the non-matching arrays, so this adapted code should do:
<?php
$fileData = file_get_contents("/tmp/post.log");
$data = json_decode($fileData, true);
// $data will now be something like this:
# $data = ["ID" => 9,"remote" => "+39123456789"]; // note, this time it's a one-dimentional (but assoc) array.
// mocking input data
# $_GET = ['ID' => 9, 'otherparam' => 'bar'];
// check if we have pre-saved data, that has an 'ID' and that matches our current one:
if(is_array($data) && isset($data['ID']) && $data['ID']==$_GET['ID']) { // the saved $ID was found -> merge new data
$data = array_merge($data, $_GET);
} else {
$data = $_GET; // create a new item, since we haven't found one
}
file_put_contents("/tmp/post.log",json_encode($data,true))); // don't append, write the whole dataset
Disclaimer: This code has no error checking whatsoever and will throw errors on a blank log (because json_decode will fail if there's no data yet), has some security issues (using $GET without sanitizing and writing that to a file...), doesn't test for proper input (what if no ID is sent), etc...
Related
I am recently facing a practical problem.I am working with ajax form submission and there has been some checkboxes.I need all checkboxes with same name as key value pair.Suppose there is 4 checkboxes having name attribute =checks so i want something like $arr['checks'] = array(value1, value2, ...)
So i am getting my ajax $_POST code as suppose like: name=alex&checks=code1&checks=code2&checks=code3
I am using below code to make into an array
public function smdv_process_option_data(){
$dataarray = array();
$newdataarray = array();
$new = array();
$notices = array();
$data = $_POST['options']; // data received by ajax
$dataarray = explode('&', $data);
foreach ($dataarray as $key => $value) {
$i = explode('=', $value);
$j = 1;
if(array_key_exists($i[0], $newdataarray)){
if( !is_array($newdataarray[$i[0]]) ){
array_push($new, $newdataarray[$i[0]]);
}else{
array_push($new, $i[1]);
}
$newdataarray[$i[0]] = $new;
}else{
$newdataarray[$i[0]] = $i[1];
}
}
die($newdataarray);
}
Here i want $newdataarray as like below
array(
'name' => 'alex',
'checks => array(code1, code2, code3),
)
But any how I am missing 2nd value from checks key array.
As I see it you only need to do two explode syntaxes.
The first on is to get the name and here I explode on & and then on name= in order to isolate the name in the string.
The checks is an explode of &checks= if you omit the first item with array_slice.
$str = 'name=alex&checks=code1&checks=code2&checks=code3';
$name = explode("name=", explode("&", $str)[0])[1];
// alex
$checks = array_slice(explode("&checks=", $str), 1);
// ["code1","code2","code3"]
https://3v4l.org/TefuG
So i am getting my ajax $_POST code as suppose like: name=alex&checks=code1&checks=code2&checks=code3
Use parse_str instead.
https://php.net/manual/en/function.parse-str.php
parse_str ( string $encoded_string [, array &$result ] ) : void
Parses encoded_string as if it were the query string passed via a URL and sets variables in the current scope (or in the array if result is provided).
$s = 'name=alex&checks=code1&checks=code2&checks=code3';
parse_str($s, $r);
print_r($r);
Output
Array
(
[name] => alex
[checks] => code3
)
You may think this is wrong because there is only one checks but technically the string is incorrect.
Sandbox
You shouldn't have to post process this data if it's sent correctly, as that is not included in the question, I can only make assumptions about it's origin.
If your manually creating it, I would suggest using serialize() on the form element for the data for AJAX. Post processing this is just a band-aid and adds unnecessary complexity.
If it's from a source outside your control, you'll have to parse it manually (as you attempted).
For example the correct way that string is encoded is this:
name=alex&checks[]=code1&checks[]=code2&checks[]=code3
Which when used with the above code produces the desired output.
Array
(
[name] => alex
[checks] => Array
(
[0] => code1
[1] => code2
[2] => code3
)
)
So is the problem here, or in the way it's constructed...
UPDATE
I felt obligated to give you the manual parsing option:
$str = 'name=alex&checks=code1&checks=code2&checks=code3';
$res = [];
foreach(explode('&',$str) as $value){
//PHP 7 array destructuring
[$key,$value] = explode('=', $value);
//PHP 5.x list()
//list($key,$value) = explode('=', $value);
if(isset($res[$key])){
if(!is_array($res[$key])){
//convert single values to array
$res[$key] = [$res[$key]];
}
$res[$key][] = $value;
}else{
$res[$key] = $value;
}
}
print_r($res);
Sandbox
The above code is not specific to your keys, which is a good thing. And should handle any string formatted this way. If you do have the proper array format mixed in with this format you can add a bit of additional code to handle that, but it can become quite a challenge to handle all the use cases of key[] For example these are all valid:
key[]=value&key[]=value //[key => [value,value]]
key[foo]=value&key[bar]=value //[key => [foo=>value,bar=>value]]
key[foo][]=value&key[bar][]=value&key[bar][]=value //[key => [foo=>[value]], [bar=>[value,value]]]
As you can see that can get out of hand real quick, so I hesitate to try to accommodate that if you don't need it.
Cheers!
I am grabbing Pokemon data from a JSON API, that is showing values for any Pokemon. The aim here is to grab data that shows what games a Pokemon can be found in and which areas in the game they are found located.
https://pokeapi.co/api/v2/pokemon/183/
This is accessed via its encounters key value. I am particularly interested in accessing via :
['location_area']['name'] and ['version']['name']
As a good URL example: https://pokeapi.co/api/v2/pokemon/183/encounters
Problem is, the encounters array index value is a URL, which I am accessing through my own Curl json function, which works fine, but will only give me array numeric index values.
public function getPokemonLocation($searchTerm)
{
/*
Get the Pokemon via search term name
*/
$url = $this->baseUrl.$searchTerm;
$pokemonLocation = $this->getUrl($url);
/*
$pokemonLocationUrl is the encounters subset i the array URL
*/
$pokemonLocationUrl = $pokemonLocation['location_area_encounters'];
$pokemonLocationEncounters = $this->getUrl('https://pokeapi.co/' . $pokemonLocationUrl);
echo "<pre>";
print_r($pokemonLocationEncounters);
echo "</pre>";
/*
Now grab the data needed from the name of location and what game regions they are from
*/
$pokemonAreaEncounterArea = array();
$pokemonAreaEncounterGame = array();
foreach($pokemonLocationEncounters as $key => $encounter)
{
$pokemonAreaEncounterArea[] = $encounter['location_area']['name'];
$pokemonAreaEncounterGame[] = $encounter['version_details'][0]['version']['name'];
}
$pokemonLocationAndRegion = array_combine($pokemonAreaEncounterGame,$pokemonAreaEncounterArea);
// print_r($pokemonLocationAndRegion);
return $pokemonLocationAndRegion;
}
Problem is, the encounters array index value is a URL, which I am accessing through my own Curl json function, which works fine, but will only give me array numeric index values.
I can easily get data, as shown above . Howwever would like to fully access all of the array indexes, not just one or a handful of data. Tempting to do this via multiple foreach, but would rather implement it cleanly.
EDIT: Here is 2nd example of Poke APi link above, if you get a 504 server Error - https://jsoneditoronline.org/?id=73911ec678c850f9b1ff131ac7ee738c
According to your json which is returning an index based array, this is how your code should be to work.
public function getPokemonLocation($searchTerm) {
/*
Get the Pokemon via search term name
*/
$url = $this->baseUrl . $searchTerm;
$pokemonLocation = $this->getUrl($url);
/*
$pokemonLocationUrl is the encounters subset i the array URL
*/
$pokemonLocationUrl = $pokemonLocation['location_area_encounters'];
$pokemonLocationEncounters = $this->getUrl('https://pokeapi.co/' . $pokemonLocationUrl);
echo "<pre>";
print_r($pokemonLocationEncounters);
echo "</pre>";
$pokemonAreaEncounterArea = array();
$pokemonAreaEncounterGame = array();
/*
Now grab the data needed from the name of location and what game regions they are from
*/
for($i=0,$size=count($pokemonLocation);$i<$size;$i++) {
$pokemonAreaEncounterArea[] = $pokemonLocation[$i]['location_area']['name'];
$pokemonAreaEncounterGame[] = $pokemonLocation[$i]['version_details'][0]['version']['name'];
}
$pokemonLocationAndRegion = array_combine($pokemonAreaEncounterGame, $pokemonAreaEncounterArea);
// print_r($pokemonLocationAndRegion);
return $pokemonLocationAndRegion;
}
to make it clearer
for($i=0,$size=count($pokemonLocation);$i<$size;$i++) {
$pokemonAreaEncounterArea[] = $pokemonLocation[$i]['location_area']['name'];
$pokemonAreaEncounterGame[] = $pokemonLocation[$i]['version_details'][0]['version']['name'];
}
this will allow you to traverse all elements in the result array, and put them on the same index in respective arrays of $pokemonAreaEncounterArea and $pokemonAreaEncounterGame
You can combine the target data as you iterate like this:
$array=json_decode($json,true);
foreach($array as $item){
$result[$item['version_details'][0]['version']['name']]=$item['location_area']['name'];
}
var_export($result);
Output:
array (
'diamond' => 'great-marsh-area-6',
'platinum' => 'sinnoh-route-215-area',
'heartgold' => 'mt-mortar-1f',
'ruby' => 'hoenn-route-120-area',
'emerald' => 'hoenn-safari-zone-expansion-south',
'leafgreen' => 'four-island-area',
'black-2' => 'route-22-area',
'x' => 'kalos-route-3-area',
)
i need to make an array like this
$privateMsgIdArray = array("idlistener" => $idlistener, "maxMsgId" => $lastMsgId);
I need to replace the maxMsgId to the corresponding idlistener, and if the idlistener that i pass doesn't not exist to create a new entry inside the array.
I am a but confused on how i am going to extract the maxMsgId value corresponding to an idlistener.
In other words i need to pass new values of idlisteners only once, and replace maxMsgId each time that they are not equal to the corresponing idlistener.
If the idlistener field doesn't exist create it (push into array).
I pass old array into a session and new array in the current run.
After the run i i replace them.
I believe this sounds a bit confusing though.
e.g
We have an array like this already:
[15][200]
next call maxMsgId is 210
array should be
[15][210]
next call we have a new listener id with maxMsgId 30
array should be
[15][210]
[16][30]
You should be able to accomplish this with a quick loop:
// your "new" values
$idListener = 15;
$maxMsgId = 210;
// loop over the array to see if it contains the `idlistener` you want
$end = count($privateMsgIdArray);
for ($i = 0; $i < $end; $i++) {
if ($privateMsgIdArray[$i]['idlistener'] == $idListener) {
// we found it! overwrite the `maxMsgId` field
$privateMsgIdArray[$i]['maxMsgId'] = $maxMsgId;
break;
}
}
if ($i == $end) {
// we reached the end of the array without finding the `$idListener`;
// add a new entry =]
$privateMsgIdArray[] = array(
'idlistener' => $idListener,
'maxMsgId' => $maxMsgId
);
}
This is a rather brute-force approach though and, if efficiency is something you're after, it would be wise to create a "cache"-style method of idlistener values and their index in the $privateMsgIdArray array.
For instance:
// key = idlistener, value = index in `$privateMsgIdArray`
$idCache = array(15 => 0, 16 => 1);
// check if the `$idListener` is in the cache
if (!isset($idCache[$idListener])) {
// it's not; add a new entry
$key = count($privateMsgIdArray);
$privateMsgIdArray[$key] = array(
'idlistener' => $idListener,
'maxMsgId' => $maxMsgId
);
// add the new index into the cache
$idCache[$idListener] = $key;
} else {
// it is in the cache; pull the corresponding index and set the `maxMsgId` =]
$privateMsgIdArray[$idCache[$idListener]]['maxMsgId'] = $maxMsgId;
}
Both of the approaches above could be converted into functions to make things "more portable" too.
ok, this might sound strange, but i have a form and our business wants to track what is getting changed, when a user adds a new lead etc.
So i set up a function that does the following
function savedata($data){
$collection = $this->db->retail_logs;
$this->data = explode('|', $data['data']);
print_r($this->data);
try {
$collection->update(
array($this->data['0']=>$this->data['1'],$this->data[2]=>$this->data[3]),
array("date"=> date("d.m.Y"), "time"=>date("H:i:s"),"whochanged"=>$_COOKIE['CRMUIDkey']), // new lead document to insert
array("upsert" => true, "safe" => true)
);
} catch (Exception $e) {
// Something went wrong ..
}
}
it is basiclly a log file.
but as you may be able to see the $data sends data though like tradingname|ABC|owner|ownerID
But if I want to add to that i would need to run a loop or a foreach I am wondering what is the best way to make sure all teh data gets saved and not just data[0] to 3 so say they send 16 fields and values in it I need a foreach or something to split it.
It appears that you want to map the $data['data'] into key=>value pairs (an associative array). You want to be very careful about what fields you allow in this format especially since it looks like user-provided data (or data they can modify in a post request?). For example, a malicious user could update or add to another user's account if you aren't checking the allowed keys before doing the upsert.
To convert the $data string you want to do something like:
<?php
// Keys that can be updated
$allowed = array('tradingname','owner');
// Sample data
$data = 'tradingname|ABC|owner|ownerID|badkey|foo';
// Split into arrays based on '|' delimiter
preg_match_all("/([^\|]+)\|([^\|]+)/", $data, $keypairs);
// Combine matches into key => value array
$keypairs = array_combine($keypairs[1], $keypairs[2]);
// Sanity check to create $criteria
foreach ($keypairs as $key => $value) {
if (in_array($key, $allowed)) {
// Perhaps do some extra sanity checking that $value is expected format
$criteria[$key] = $value;
} else {
// Log and/or bailout as appropriate
echo "Ignoring: [$key] => [$value]\n";
}
}
// Criteria should now be reasonable to use in $collection->update(..) upsert
print_r($criteria);
?>
Send your data as json. And then use json_decode to convert it to the array you want.
I thought this would be simple but I cant seem to get it to work. All I want to do is to add a value into a userdata array. If a value is already in the viewed_news_items array I do not want to replace it.
$data = array(
'username' => $this->input->post('username'),
'is_logged_in' => true,
'viewed_news_items' => array()
);
$this->session->set_userdata($data);
insert value into viewed_news_items array
$a = array($desk_id => $desk_id);
$this->session->set_userdata('viewed_news_items', $a);
You're using $desk_id as both the key and value, meaning unless you already have the value of $desk_id, you won't be able to look it up in the array.
Instead of this:
$a = array($desk_id => $desk_id);
You probably wanted to do this:
$a = array('desk_id' => $desk_id);
That is, use the string 'desk_id' as the key whose corresponding value is $desk_id.
Is there a way to have the 'desk_id' just as an auto number so each time the code is executed another value is added instead of replacing 'desk_id'?
You can push items onto the end of an array via array_push($array, $value) or $array[] = $value. PHP will automatically assign the next numeric ID as the index for the new array element.
In your current scenario, you'll have to pull the existing list of IDs out of the session, append an ID to it, and then put it back into the session:
# pull the existing IDs out of the session
$viewed_news_items = $this->session->userdata('viewed_news_items');
# on first load, the array may not be initialized
if (!is_array($viewed_news_items))
$viewed_news_items = array();
# append $desk_id to the list of viewed items
$viewed_news_items[] = $desk_id;
# put the new list back into the session
$this->session->set_userdata('viewed_news_items', $viewed_news_items);
invoke the type of data you retrieved from session
and use it as you want.
$ID = 123;
$data = (array)$this->session->userdata("session_name");
$data[] = $ID;
$this->session->set_userdata("session_name",$data);