Okay. Now I give up. I have been playing with this for hours.
I have a variable name $data.
The variable contains these contents: (extracted by using var_export())
array (
'headers' =>
array (
'content-type' => 'multipart/alternative; boundary="_689e1a7d-7a0a-442a-bd6c-a1fb1dc2993e_"',
),
'ctype_parameters' =>
array (
'boundary' => '_689e1a7d-7a0a-442a-bd6c-a1fb1dc2993e_',
),
'parts' =>
array (
0 =>
stdClass::__set_state(array(
'headers' =>
array (
'content-type' => 'text/plain; charset="iso-8859-1"',
'content-transfer-encoding' => 'quoted-printable',
),
'ctype_primary' => 'text',
)),
),
)
I removed some non-essential data.
I want to access the headers value (on the second line above) - simple: $data->headers
I want to access the headers value (on the fourteenth line after the stdClass:: stuff) - how?
How can I possibly access the values within the stdClass::__set_state section?
I tried var_export($data->parts); but all I get is
NULL
Is this variable declared the way you posted it? Like:
$data = array(
'headers' =>
array (
…
In that case, I'm not quite sure how you can access 'headers' via $data->headers. It should be $data['headers'], because it is an array, not an object.
Further down, stdClass::__set_state(array('headers' => …)) statically calls the method __set_state of the class stdClass. Whatever this method does I don't know, but only its return value will be assigned to the 'parts' => array(0 => ...) key.
If OTOH what you're showing is the result of var_dump($data), then this is incorrect nonsense, since stdClass::__set_state() would never show up in a var_dump. Something is fishy either in your code or in what you posted and it's hard to say without seeing more of it.
Disregard the above, var_export prints classes this funky way.
$data['headers'] should do it for the first headers part. Further down, $data['parts'][0]->headers should do the trick.
I ran into a similar problem with the open-source mail server Postal. In this case, I used the API to send an email message with two recipients. The API returns JSON, which I want to process to get the message ID Postal has assigned to each message. The JSON string decodes to a series of nested objects, according to print_r.
pObj: stdClass Object
(
[status] => success
[time] => 0.28
[flags] => stdClass Object
(
)
[data] => stdClass Object
(
[message_id] => a122e786-6c32-4085-b1ed-023e5923ca38#rp.postal.domain.com
[messages] => stdClass Object
(
[name1#domain1.com] => stdClass Object
(
[id] => 180
[token] => AblVpj6UW2wh
)
[name2#domain2.com] => stdClass Object
(
[id] => 181
[token] => io5wgEXO1boH
)
)
)
)
Looking at the structure, the first few layers are easy to extract. The trouble is that the messages object has attributes named for each recipient email address. Without knowing these address values a priori, I couldn't access the individual recipient objects programmatically to get at the message id.
I also examined this object using var_dump() and var_export(). That's where I saw this strange and misleading syntax: "stdClass::__set_state(array(". But there are no arrays at all in this object. In reality, this structure contains nothing but nested objects and attributes.
This situation was giving me fits until I asked the right question: what are the names of an object's attributes?
Now the programmatic solution is relatively easy because PHP has a function for that. I used get_object_vars() to get an array of attributes in the messages object. By simply looping on that array, I could then access the id and token attributes of each address. Here's the code, with a sample JSON response from Postal.
define('_EOL', "\n");
$json='{"status":"success","time":0.28,"flags":{},"data":{"message_id":"a122e786-6c32-4085-b1ed-023e5923ca38#rp.postal.domain.com","messages":{"name1#domain1.com":{"id":180,"token":"AblVpj6UW2wh"},"name2#domain2.com":{"id":181,"token":"io5wgEXO1boH"}}}}';
$pObj=json_decode($json);
$str='<pre>pObj: '.print_r($pObj, true)._EOL._EOL;
$str.=' - status='.$pObj->status._EOL;
$msgVars=get_object_vars($pObj->data->messages);
foreach ($msgVars as $varKey=>$msgObj)
{
$str.=' - '.$varKey.':'._EOL;
$str.=' - id='.$msgObj->id._EOL;
$str.=' - token='.$msgObj->token._EOL;
}
echo($str.'</pre>');
What made this hard is that the Postal design uses variable attribute names in the messages object. I would have made messages an array and put the email address into an attribute named address along with the attributes id and token. But it is what it is, and I hope this helps someone else.
Related
I have a php stdObject that is an object, and sometimes an array of Objects.
EDIT: It's been returned by SoapClient::__soapCall.
If it has one entry:
stdClass Object
(
[Event] => stdClass Object
(
[Nr] => 7050
[Date] => 2016-11-30T00:00:00
)
)
If it's got multiple entries:
stdClass Object
(
[Event] => Array
(
[0] => stdClass Object
(
[Nr] => 7015
[Date] => 2016-04-28T00:00:00
)
[1] => stdClass Object
(
[Nr] => 7016
[Date] => 2016-04-29T00:00:00
)
[2] => stdClass Object
(
[Nr] => 7017
[Date] => 2016-06-08T00:00:00
)
)
)
I don't see why, and I'd like to correct it.
Here's how I got there:
$items = $this->getAll(); // returns an Object with n entries
foreach($items as $item){
$fullItem = $this->item->getElementByID($item->Nr); // returns the full data for this entry
$item->Days = $fullItem->Days; // that's the one that can contain objects or just the data if it has one entry
}
My Questions:
Is that normal, that the same request returns different data types?
Should I "normalize" this and make an array of objects if there's only one entry?
Or is there an other recommended way to cope with it?
I don't think it's ok in this case. You should keep the interface the same. So if you are expecting an unknown number of elements it should always be a collection, even if in some cases only one element is returned. However if you expect only one element then the collection should be omitted.
$this->getAll(); //should always return a collection
$this->getOneById($id); //should return single item without collection, return null or throw exception if no element is found
On the question should you "normalize" (refactor) it I wold say it depends on the effort estimation and the benefit you'll gain form the refactoring. If this occurs in few places only and it's not likely to be used in any other place in the future I think you shouldn't bother. In case you decide to refactor be very careful and ensure the whole application is working properly. If you have tests - great.
I didn't declare it in the question, sorry: The data is the result of a soap client call:
$this->soapClient = new \SoapClient($wsdlUrl, array('trace' => DEBUG_SOAP));
// ...
$result = $this->soapClient->__soapCall($method, array($method => $params));
I think what confused me is the standard behaviour of SoapClient::__soapCall
SOAP functions may return one, or multiple values. If only one value
is returned by the SOAP function, the return value of __soapCall will
be a simple value (e.g. an integer, a string, etc). If multiple values
are returned, __soapCall will return an associative array of named
output parameters.
http://php.net/manual/en/soapclient.soapcall.php
Also, a very similar question: PHP SoapClient type mapping behaves differently
And here are two solutions from there:
"Normalize" (what's the correct word?) the data AFTER we got it:
if (is_object($variable)){
$variable = array($variable);
}
https://stackoverflow.com/a/6408780/160968
And, that would be the equivalent to refactoring the request BEFORE we get it – there's a setting for the soapClient!
$soapConfig = array(
'features' => SOAP_SINGLE_ELEMENT_ARRAYS,
'trace' => true
);
$client = new SoapClient($wsdlUrl, $soapConfig);
https://stackoverflow.com/a/8008715/160968
Awesome!
How will i be able to get a single value out of BTC-e API using PHP?. This is the current API that i can use.
https://btc-e.com/api/3/ticker/btc_usd
As you can see, it shows lots of information, but i dont need many information that is displayed there. What can i do so that i will only get
"last":284.323
this number?
Thank you for your help regarding this subject.
As you can see, the received data is a JSON value.
If you simply want to receive data from a website, you can use the file_get_contents function.
With the json_decode function, you can create an object from this data.
If you're looking for a specific value, you maybe can use print_r to get a clarifying list of the given data.
When you use the print_r function on the given data, it will return:
stdClass Object
(
[btc_usd] => stdClass Object
(
[high] => 288.957
[low] => 272.00201
[avg] => 280.479505
[vol] => 2178508.65397
[vol_cur] => 7771.83325
[last] => 286.322
[buy] => 286.328
[sell] => 286.322
[updated] => 1445787588
)
)
As you can see, you are looking for a variable stored in ->btc_usd->last
So when it all comes together, you can use the following:
<?php
# Get String
$_ApiString = '{"btc_usd":{"high":288.957,"low":272.00201,"avg":280.479505,"vol":2178508.65397,"vol_cur":7771.83325,"last":286.322,"buy":286.328,"sell":286.322,"updated":1445787588}}';
# Or maybe you simply want to download it from a website
$_ApiString = file_get_contents('https://btc-e.com/api/3/ticker/btc_usd');
# Create object from ApiString
$_Object = json_decode($_ApiString);
# Get variable
$_Last = $_Object->btc_usd->last;
?>
Please check the below array:
Array([bunrey] => Array ([0] => 20130730181908615391000000)
[mt.shasta] => Array (
[0] => 20130708203742347410000000
[1] => 20130213201456984069000000
[2] => 20130712144459481348000000
)
[shingletwon] => Array
(
[0] => 20130801233842122771000000
)
)
I want to send this array as query string using http_build_query(),
I got the below string after using http_build_query():
bunrey%5B0%5D=20130730181908615391000000&mt.shasta%5B0%5D=20130708203742347410000000&mt.shasta%5B1%5D=20130213201456984069000000&mt.shasta%5B2%5D=20130712144459481348000000&shingletwon%5B0%5D=20130801233842122771000000
As you can see after sending this query string to some other file, there I am trying to retrieve. I had echoed the $_REQUEST object:
Array (
[bunrey] => Array
(
[0] => 20130730181908615391000000
)
[mt_shasta] => Array
(
[0] => 20130708203742347410000000
[1] => 20130213201456984069000000
[2] => 20130712144459481348000000
)
[shingletwon] => Array
(
[0] => 20130801233842122771000000
)
)
please check one of the key mr.shasta had changed to mr_shasta.
Can you people please provide any solution for this.
This is the standard PHP behaviour. Points are converted in underscores when used as array keys in a POST request.
From the documentation:
Dots and spaces in variable names are converted to underscores. For
example < input name="a.b" /> becomes $_REQUEST["a_b"].
The only solution is: stop using spaces and/or dots in array keys when using them in POST requests or, else, operate a string replace on every array key your receive.
$post = array();
foreach ($_POST as $key => $value)
$post[str_replace("_", ".", $key)] = $value;
Note that the code above would fix only the problem of . (converted to _) but not spaces. Also, if you have any _ in your original key this would be converted to . as well (as pointed out in the comments).
As you can see, the only real solution is to avoid . and spaces in $_POST keys. They just can't be received, not with PHP (and not with other server-side solutions that I know of): you'll loose that information.
No, this is not a limitation or a crap feature: this is a programming guideline. If you're using array keys names for something more than what you would normally do with a variable name, you're most likely doing something conceptually wrong (and I've done it many times too).
Just to give you an example on how wrong is that: in some programming solutions like asp.net-mvc (and, I think, codeigniter too) POST/GET requests are supposed to be mapped over functions in what's called a "controller". Which means that if you send a POST which looks like ["myKey" => "myValue", "myOtherKey" => "someValue"] you should then have a function which takes keys as arguments.
function(String myKey, String myOtherKey){ }
PHP have no default "on-top" framework (that I know of) which do this: it allows you to access $_POST directly. Cool: but this toy can breake easely. Use it with caution.
I may be wrong here, but I've replicated what you're doing and have found it depends how you assign the array as to whether or not it changes the key like this:
//doesn't change to mt_shasta
$array['bunrey'][0] = 20130730181908615391000000;
$array['bunrey']['mt.shasta'][0] = 20130708203742347410000000;
$array['bunrey']['mt.shasta'][1] = 20130708203742347410000000;
$array['bunrey']['mt.shasta'][2] = 20130708203742347410000000;
$array['bunrey']['shingletwon'][0] = 20130708203742347410000000;
//does change to mt_shasta
$array = array (
'0' => 20130730181908615391000000,
'mt.shasta' => array (
0 => 20130708203742347410000000,
1 => 20130213201456984069000000,
2 => 20130712144459481348000000,
),
'shingletwon' => array
(
0 => 20130801233842122771000000,
),
);
I've searched a lot for this, and found several similar questions, but none quite address what I'm trying to accomplish.
I'm trying to write a code that will search a PHP (multi)multidimensional array to see which subarray contains the unique key value that I have. Then I would like it to return the value of a different key in that same object subarray.
$Arraytosearch = Array(
.
//various other subarrays
.
[fields] => Array (
.
.
.
//I don't know the number of the object subarray
[x] => PodioTextItemField Object (
[__attributes] => Array (
[field_id] => 37325091
[type] => text
[external_id] => id
[label] => ID
[values] => Array (
[0] => Array (
[value] => REF100019 ) )
[config] => Array (
[description] => [settings] => Array (
[size] => small )
[required] => [mapping] => [label] => ID [visible] => 1 [delta] => 2 ) )
.
.
.
//(and so on)
I'd like to write a function that will return "REF100019" by supplying the value of the field_id => 37325091.
Some things I have tried that I couldn't get to work:
foreach
and new RecursiveIterator although the tutorials I read weren't useful for my case here.
Even though the array looks complicated, I think it will be easy since I already have the field id of the parent array.
Thank you in advance for any guidance or sample codes that will work!
Background: This is a part of the response I get from Podio after submitting a request to their API. I just don't know how to take that response and get the piece I need (the ID) so that I can echo it for users).
EDIT: Thank you Orangepill and Barmar for the support. I tried your code. But was getting an error, which made me realize I hadn't given you the full array. I figured out how to get the Podio response to display in a more readable format (I was reading the full JSON response before from the Podio debug file which was super confusing), and figured out the full array is actually structured as I have shown below.
I then took your code and was able to figure out how to make it work for my scenario (see below). Very proud of myself considering I have never written any code before, but I couldn't have done it without your help! Thanks again!
$Arraytosearch = Array(
[items] => Array(
[0] => PodioItem Object(
[_attributes] => Array(
[fields] => Array (
[x] => PodioTextItemField Object (
[__attributes] => Array(
[field_id] => 37325091
[values] => Array(
[0] => Array(
[value] => REF100019 ) )
Note: For anyone who is new to programming like myself and wants the Podio response (or any JSON string) to display in a "pretty" readable format like above, use the code (from Display an array in a readable/hierarchical format thanks to Phenex):
print "<pre>";
print_r($Arraytoformat);
print "</pre>";
And finally, the full code I used (using Orangepill's answer below) which searches the objects and arrays and gives me what I have been searching for for days now is as follows:
$Arraytosearch = PodioItem::filter(APP_ID, $filterParams);
$fieldID = 37325091;
function getFirstValueByFieldId($fieldId, $Arraytosearch){
foreach($Arraytosearch["items"][0]->__attributes["fields"] as $textitem){
if ($textitem->__attributes["field_id"] == $fieldId){
return $textitem->__attributes["values"][0]["value"];
}}}
$refID = getFirstValueByFieldId($fieldID, $Arraytosearch);
The podio-php library has built-in methods that handle all this for you. There's no need to mess with the __attributes property yourself.
You can see a bunch of examples at https://github.com/podio/podio-php/blob/master/examples/items.php
In your case:
// Get item collection
$itemCollection = PodioItem::filter(APP_ID, $filterParams);
$fieldID = 37325091;
foreach ($itemCollection['items'] as $item) {
// Get the field from the item
$field = $item->field($fieldID);
// Now you can print the value of that field
print $field->humanized_value;
// Or if you don't want to have the content sanitized:
print $field->values[0]['value'];
}
There is a lot of ways to skin this cat... this is probably the most straight forward
function getFirstValueByFieldId($fieldId, $Arraytosearch){
foreach($Arraytosearch["fields"] as $textitem){
if ($textitem->__attributes["field_id"] == $fieldId){
return $textitems->__attributes["values"][0]["value"];
}
}
}
to Use in your case would be
echo getFirstValueByFieldId("37325091", $Arraytosearch);
Basically it walks the elements in the fields array and returns the value in the first associated value in the values array where field_id is equal to the parameter of the function.
Sorry for asking a basic question like this but I've been reading on this for a few hours now and the examples aren't making sense to me in context of the way my array is.. I have been able to pass this from my server side (cakephp) to the javascript (I'm using jquery) but after that, I am lost as to how to make use of the data.. I tried just showing it using an alert, but it gives output like "object Object" and thats all..
This is an example array that I have:
Array (
[0] => Array ( [Uiemail] => Array ( [uiemail_id] => 2 [divid] => upd1 [width] => 200 [height] => 200 [leftpos] => 122 [toppos] => 122 [cssgroup] => 1 [colortop] => [colorbottom] => [colorborder] => [borderwidth] => [zindex] => ) )
[1] => Array ( [Uiemail] => Array ( [uiemail_id] => 3 [divid] => upd2 [width] => 200 [height] => 200 [leftpos] => 333 [toppos] => 444 [cssgroup] => 1 [colortop] => [colorbottom] => [colorborder] => [borderwidth] => [zindex] => ) )
[2] => Array ( [Uiemail] => Array ( [uiemail_id] => 4 [divid] => upd3 [width] => 200 [height] => 200 [leftpos] => 555 [toppos] => 466 [cssgroup] => 1 [colortop] => [colorbottom] => [colorborder] => [borderwidth] => [zindex] => ) )
)
EDIT:
The array is the way it is as its the output from a Cakephp database GET (cakephp's equivalent of this).
It has 3 arrays, the first is the "parent array" and contains the [1], [2], [3] which are like an auto-increment ID for the 2nd tier arrays.
The 2nd tier has an array that holds the 3rd, this second doesn't really contain any data other than the 3rd array (its done like this by cakephp since its representing the database table)
So, the 3rd tier array has all the data that I need, however I also would want to use the first tier ID
IN PHP A INDIVIDUAL PIECE OF DATA FROM THIS ARRAY IS ACCESSED AS SUCH:
$arrayline = [0]['Uiemail']['toppos'];
Here is some javascript I tried that didn't work (json is array name):
$(json).each(function() {
alert(this.text)
});
});
Thanks for any advice, its just that my array is a nested array (as its from a database call) and it seems most examples don't go this deep which is leading me to confusion.
An 'associative array' in PHP (i.e. with meaningful keys like your 'uiemail_id' will become an object in JSON notation. Even an array that is not exactly 0-indexed & continuous will also become one. (i.e. an array with keys 0,1,2 will result in an array, keys 1,2,3 or 0,2,3 will result in an object.
If you access a value in PHP like this:
$arrayline = $array[0]['Uiemail']['toppos'];
The access on the resulting structure in js would be:
arrayline = jsonvar[0].Uiemail.toppos;
Enabing firebug in firefox, with breakpoints, lets you easily inspect any variable available at that moment at your leisure, which makes it a far easier to debug then the usual default PHP way of just dumping variable notation to stdout (i.e. printr / var_dump's).
Try this:
$.each(json, function(index, element){
alert(element);
});
if json is your javascript object which (hopefully) already was parsed as json, you can't call the jQuery constructor function on it and expect it to work like this.
Use the $.each() helper function to iterate over an object with jQuery.
If you still got [object Object] as alert, it's because those sub elements are Arrays or real Objects themself, so you need to dig deeper. Good help is FireBug and console.dir()
Reference: $.each()
I don't really understand your array notation...but my guess is that the representation in json/javascript would be:
[
[[2, 'udp1', 200, 200, 122, ....]],
[[3, 'udp2', 200, 200, 333, ....]],
[[4, 'udp3', 200, 200, 555, ....]]
]
When you pass an array in json, the 'index names' aren't passed.
If this is the structure, then something like this might get something:
$.each(json, function(index, element){
$.each(element, function(index, sub){
alert(sub);
});
});
You have to use jQuery.each() for that.