Getting data from WP database when info is not constant - php

This is my array:
Array
(
[0] => Array
(
[id] => 1387
[form_id] => 2
[date_created] => 2018-05-17 21:34:37
----> [67] => a:1:{i:0;a:7:{s:17:"wp_attachement_id";i:5828;s:9:"mime_type";s:9:"video/mp4";s:9:"file_path";s:89:"/home/xxx/public_html/wp-content/uploads/2018/05/703c94b2b97a6479113d9e3020952891.mp4";s:5:"title";s:3:"xxx";s:11:"description";s:3:"xxx";s:8:"video_id";s:6:"QRSTUV";s:9:"video_url";s:43:"https://www.youtube.com/watch?v=QRSTUV";}}
[36] => New Harpshire
[34] => Borristown
)
)
The following will print the video id:
$undid = unserialize($entry['0']['67']);
echo $undid['0']['video_id'];
The problem is the number '67' does not remain constant. How do I retrieve that video_id if I have no idea what '67' will be?

I whipped up a quick Demo for you.
Ideally, you'd find a way to set the key to a semantic name instead of '67'. But if you can't, and it's always different, then your best bet is to check for the expected value.
Since you're expecting a serialized array, we can check for serialized values by running them through the unserialize() function. Note: This will trigger E_NOTICE level errors, so you'll probably want to suppress those with #unserialize() (the # suppresses errors). While it's generally a bad idea to suppress errors, these are errors we're expecting to trigger, so they should be safe to ignore.
So, as we pass things through unserialize(), we can check if it sets $undid to a truthy value. Once it does, we need to make sure we have the correct serialized information, so we can see if $undid[0]['video_id'] is set, and if it is, echo that value (or whatever else you want to do with it), and then break the foreach loop, since it no longer needs to run once our conditions have been met.
It's not exactly the most beautiful solution, but unless you can figure out how to name that key something semantic like file_upload_array, your best bet is loop through the values until you find the one you need. As long as you don't have an unthinkable amount of fields, this should work fairly quickly.
$entry = [
[
'id' => 1387,
'form_id' => 2,
'date_created' => '2018-05-17 21:34:37',
'67' => 'a:1:{i:0;a:7:{s:17:"wp_attachement_id";i:5828;s:9:"mime_type";s:9:"video/mp4";s:9:"file_path";s:89:"/home/xxxxxxx/public_html/wp-content/uploads/2018/05/703c94b2b97a6479113d9e3020952891.mp4";s:5:"title";s:3:"xxx";s:11:"description";s:3:"xxx";s:8:"video_id";s:6:"QRSTUV";s:9:"video_url";s:43:"https://www.youtube.com/watch?v=QRSTUV22222";}}',
'36' => 'New Harpshire',
'34' => 'Borristown',
]
];
foreach( $entry[0] as $key => $val ){
if( $undid = #unserialize( $val ) ){ // unserialize returns E_NOTICE warnings on non-serialized items. # suppresses that.
if( isset( $undid[0]['video_id'] ) ){ // Make sure this is the correct serialized field
echo $undid[0]['video_id'];
break;
}
}
}

Related

Simplify PHP array with same items

I have this PHP array:
$this->user_list = array( 0 => 'Not paid',1 => 'Not paid', 2 => 'Not paid', 7 => 'Waiting, 15 => 'Waiting', 10 => 'Cancelled' );
How can I simplify this array as the id numbers are different, but some of them have same status?
I tried it like this:
$this->user_list = array( [0,1,2 => 'Not paid'],[7,15 => 'Waiting'],10 => 'Cancelled' );
but it doesn't work as expected.
Basically I want to achieve this:
echo $this->user_list[15] should give me Waiting, echo $this->user_list[10] should give me Cancelled, etc. So this is working in my first array very well, I am just thinking about grouping duplicate names there.
As mentioned by other contributors, there is no native support in the PHP grammar for your intended use case. As clearly stated in the PHP: Arrays documentation:
An array can be created using the array() language construct. It takes any number of comma-separated key => value pairs as arguments.
So basically each element in an array is a key => value pair, which means you cannot associate multiple keys to a single element.
This also explains why your first tentative didn't work:
$this->user_list = array( [0,1,2 => 'Not paid'],[7,15 => 'Waiting'],10 => 'Cancelled' );
If you don't specify a key for an element, PHP uses a progressive index (0, 1, ...). So basically in the example above, the first zero is not actually a key, but a value, and PHP binds it to the key = 0. Maybe it could be easier for you to understand how it works if you print a var_dump or print_r of $this->user_list. You would get something similar to the following structure (NOTE: I have simplified the structure to make it more clear):
[
0 => [
0 => 0
1 => 1
2 => "Not paid"
],
1 => [
0 => 7,
15 => "Waiting"
],
10 => "Cancelled"
]
So how do we resolve this problem? Well... actually there is no need to contort the structure by swapping keys with values as other contributors seem to suggest. Changing the structure might simplify your "data entry" work but might also create big issues in other parts of the program because who knows, maybe accessing the invoice data by "ID" is simply more efficient than by "status" ... or something.
Since PHP does not provide such a feature out of the box, I believe a better solution would be to develop our own function; a good starting point could be the one in the example below.
function explode_array($config, $sep = ',') {
$res = [];
foreach($config as $configKey => $value) {
// split key values
$keys = explode($sep, $configKey);
foreach($keys as $key) {
$res[$key] = $value;
}
}
return $res;
}
$config = [
'0,1,2' => 'Not paid',
'7,15' => 'Waiting',
'10' => 'Cancelled'
];
$myArr = explode_array($config);
print_r($myArr);
The idea is quite simple: since we cannot use an array as key we leverage the next best data type, that is a CSV string. Please note there is no error handling in the above code, so the first thing you may want to do is adding some validation code to the explode_array (or however you wish to name it) function.
you should use like this. if id number is invoice id or something else and other value is there status about it.
$arr = array(
'Not paid' => [0,1,2] ,
'Waiting' => [5,6],
'Cancelled' =>[8]
);
foreach($arr as $key => $val){
foreach($val as $keys => $vals){
echo "invoiceid ".$vals ." status ".$key;
echo"<br>";
}
}
// for only one status you can use like this
foreach($arr['Not paid'] as $key => $val){
echo $val;
echo"<br>";
}
just try to run this and check output.
PHP has no built-in function or structure for handling cases like this. I'd use a simple array value-cloning function to map your duplicates. Simply have one instance of each status, then map the aliases, and then run a function that clones them in. As follows:
// Status list:
$ulist = [ 0 => 'Not paid', 7 => 'Waiting', 10 => 'Cancelled' ];
// Alternative IDs list, mapped to above source IDs:
$aliases = [ 0 => [1,2], 7 => [15] ];
// Function to clone array values:
function clone_values(array &$arr, array $aliases)
{
foreach($aliases as $src => $tgts) {
foreach($tgts as $tgt) {
$arr[$tgt] = $arr[$src];
}
}
ksort($arr); // If the order matters
}
// Let's clone:
clone_values($ulist, $aliases);
This results in the following array:
array(6) {
[0] · string(8) "Not paid"
[1] · string(8) "Not paid"
[2] · string(8) "Not paid"
[7] · string(7) "Waiting"
[10] · string(9) "Cancelled"
[15] · string(7) "Waiting"
}
....which can be accessed as you expect, here $ulist[2] => Not paid, etc. If the use case is as simple as illustrated in the OP, I'd personally just spell it out as is. There's no dramatic complexity to it. However, if you have dozens of aliases, mapping and cloning begins to make sense.
As said in the comments, you can't have multiple keys with one value. The best way is to use the keyword => [ number, number, number...] construction.
//set a result array
$result = [];
//loop the original array
foreach ( $this->user_list as $number => $keyword ){
//if the keyword doesn't exist in the result, create one
if(!isset ( $result [ $keyword ] ) ) $result[ $keyword ] = [];
//add the number to the keyword-array
$result[ $keyword ] [] = $number;
}

Get value from an array PHP - illegal offset

This is the print_r from the $form_data variable / array in php log.
[28-Sep-2018 18:04:03 UTC] Array
(
[cfdb7_status] => unread
[meno] => data
[email] => data
[telefon] => phone
[meno-ucastnika__1] => data
[email-ucastnika__1] => data
[meno-komory__1] =>
[registracne-cislo__1] =>
[_wpcf7_groups_count] => Array
(
[emails] => 1
)
[obchodne-meno] => obchod
[obchodne-sidlo] => fs
[ico] => 50426508
[dic] => dic
[icdph] => icdicko
)
How can I get the value of _wpcf7_groups_count key?
If I want email I simply wrote $form_data['email']. Everything goes like this except _wpcf7_groups_count.
$form_data['_wpcf7_groups_count']
$form_data['_wpcf7_groups_count'][0]['emails']
$form_data['_wpcf7_groups_count']['emails']
Anything from above doesn't work. The first is giving me an illegal offset.
From the data you posted(*),
$form_data['_wpcf7_groups_count']['emails']
should work, and yield 1.
Note that the parent key value is an array, so if the form data goes through some sort of templating engine, the problem might lie there.
I find it strange that you get an error for the first method, and not for the others: in PHP, if you can't reference an array key, you cannot reference any of the descendants, and you still get the error from the parent key. This is what makes me suspect that something else is afoot.
==========
(*) I assumed that you have deleted some information while keeping the formatting. Otherwise writing
[meno-komory__1] =>
[registracne-cislo__1] =>
could possibly be interpreted as a nested key. I saw no 'Array', so I assumed there was just some data missing. But next time write it explicitly to avoid any ambiguity:
[meno-komory__1] => "(redacted)",
[registracne-cislo__1] => "(array, redacted)",

Array of objects not altered after first file write

I have an empty array in a remote file but intend to momentarily add and alter objects in it. However, after adding an initial first set of objects, the array does not accept any more values. My error log reports unexpected 'Object' (T_STRING), expecting ')' meaning it regards the keyword "Object" as a string imputed by me so I guess the problem originates from my array structure. Here is the code I used in adding the objects
include 'all_users.php';
$francis_udeh = new Admin("francis_udeh");
$all_users['francis_udeh'] = $francis_udeh;
$victor_nwafor = new Member("victor_nwafor");
$all_users['victor_nwafor'] = $victor_nwafor;
$print_arr = print_r($all_users, TRUE);
$updated_arr = "<?php \n \$all_users = $print_arr; \n?>";
file_put_contents('all_users.php', $updated_arr);
returns the following in the remote file
<?php
$all_users = Array
(
[francis_udeh] => Admin Object
(
[name] => francis udeh
[pagename] => francis.udeh
[can_comment] => 1
[can_view_announcements] => 1
[profile_pic] => /blog/accounts/assets/user.png
[can_delete_comment] => 1
)
[victor_nwafor] => Member Object
(
[name] => victor nwafor
[pagename] => victor.nwafor
[can_comment] => 1
[can_view_announcements] => 1
[profile_pic] => /blog/accounts/assets/user.png
)
);
?>
(which, by the way, is what I want). However, when I try
include 'all_users.php';
$raheem_sadiq = new Member("raheem_sadiq");
$all_users['raheem_sadiq'] = $raheem_sadiq;
$print_arr = print_r($all_users, TRUE);
$updated_arr = "<?php \n \$all_users = $print_arr; \n?>";
file_put_contents('all_users.php', $updated_arr);
it returns the error I posted earlier resulting in the array not changing. What am I doing wrong?
You include all_users.php at the beginning of code, but after first file_put_contents() it's a not correct php code in this file.
As #Indra already mentioned: the output given by print_r() is human readable, but not valid php code. If you don't have the possibilty to pass the data via a data storage (like mysql), it might be a workaround to put it to the file with serialize(). Alternatively, you could also use json (as your objects seem to be data access objects of some same kind) and then instantiate the objects remotely.
Hope this helps,
Greetings

Check if value exists in array before inserting into database

I have an array that is returned from an API although some keys/values are not present all of the time.
example array
Array
(
[example0] => data
[example1] => data
[example2] => data
[example3] => data
)
Now if I use a query such as below
$dbh = $this->database->prepare("INSERT INTO table(example0, example1, example2, example3)VALUES(:example0, :example1, :example2, :example3)");
$dbh->execute(array(
"example0" => $data['example0'],
"example1" => $data['example1'],
"example2" => $data['example2'],
"example3" => $data['example3']
));
It will work fine. But when the API returns an array like
Array
(
[example0] => data
[example1] => data
[example3] => data
)
It will cause an error due to a value not being set, is there a way to just have it enter nothing into the column rather than throw an error? I am using a really big query for this so writing an if/else for each value would not be a good idea (in my opinion, for performance wise)
You have to check if the key is set and eventually is there is a value:
if(isset($array['your_key']) && !empty($array['your_key'])) { }
I cannot make it clear from your code but validate everything before you use it in a query.
[Edit] Example:
$keys = array('example1', 'example2', 'example3', 'example4');
$use_in_query = array();
foreach($keys as $key)
{
if(isset($array[$key]) && !empty($array[$key])) $use_in_query[$key] = $array[$key];
}
Now you can use the $use_in_query var in your query.
$dbh->execute($use_in_query);
[/Edit]

CakePHP overriding identical "field" in search conditions

I've come across an odd problem using CakePHP 1.3 to find information. Let's use this dbschema as an example:
id is int(11) PRIMARY auto_increment
amount is float(10,2) NULL
status is ENUM(Completed, Removed, Pending)
id amount status
1 100.00 Completed
2 100.00 Removed
3 100.00 Completed
4 100.00 Completed
5 100.00 Pending
When using Cake's find to retrieve data from this table, I use this query:
$this->Testtable->find('all', array(
'conditions' => array(
'status LIKE ' => 'Removed',
'status LIKE ' => 'Pending',
'status LIKE ' => 'Completed'
)
))
Looking at this query, I would assume that Cake would return all rows that match all of those conditions (which is totally acceptable in SQL), however it only uses the last condition and returns WHERE status LIKE 'Completed'.
I ran a test doing this, which returned all rows correctly (I know it's a more "correct" way to do the query anyway):
'conditions' => array(
'status' => array('Removed', 'Pending', 'Completed')
)
Take the opposite for an example, I want to return all rows that aren't Removed or Pending:
'conditions' => array(
'status !=' => 'Removed',
'status !=' => 'Pending'
)
This query returns all rows with Completed and Removed, as it only listens to the last statement. I assume that this is happening because instead of concatenating these search conditions into the query, Cake is overwriting the conditions based on the "field" being status !=. I can prove this theory by adding a space after the != in either of those conditions, creating the desired result of only Confirmed records.
Can anybody tell me why Cake would do this? As this is a legitimate thing to do in SQL, I see no reason that Cake wouldn't allow you to do it. Does anybody know if this issue is fixed up in newer versions of Cake?
I suppose that this comes down to the fact that at the end of the day, I am reassigning the array value based on that key, and it's not actually CakePHP's fault at all. I had a look into Cake's model.php and found this:
$query = array_merge(compact('conditions', 'fields', 'order', 'recursive'), array('limit' => 1));
I ran a test:
$array = array(
'conditions' => array(
'test' => 'yes',
'test' => 'no'
)
);
$var = 'hello';
$c = compact('array', 'var');
print_r($c);
As mentioned above, compact is only receiving the value no from the test key. I assumed that the use of compact to merge variables/arrays into the query would recursively merge similar keys from the conditions array into the last specified, but it turns out that yes isn't even making it that far as it's being redefined on the spot.
I suppose this is a limitation of PHP rather than Cake, but it is still something that didn't occur to me and should be done differently somehow (if it hasn't already) in future.
Edit
I ran a couple more tests. I wrapped identical conditions in their own arrays, then compared them the way Cake's find functions would. Using compact (which Cake does) the arrays containing identical keys remain intact, however using array_merge, the first key is overwritten by the second. I guess in this case it's a very, very good thing that Cake uses compact instead of array_merge to merge its query criteria.
$array = array(
array('test' => 'yes'),
array('test' => 'no')
);
$m = array_merge($array[0], $array[1]);
$c = compact('array');
print_r($c);
print_r($m);
Result:
Array
(
[array] => Array
(
[0] => Array
(
[test] => yes
)
[1] => Array
(
[test] => no
)
)
)
Array
(
[test] => no
)
While this is obviously a simple problem in the way you fundamentally write PHP code, it wasn't inherently obvious while writing in Cake syntax that conditions would overwrite each other...
Basic PHP: Don't use the same array key twice
'conditions' => array(
'status LIKE ' => 'Removed',
'status LIKE ' => 'Pending',
'status LIKE ' => 'Completed'
)
should be
'conditions' => array(
'status LIKE' => array('Removed', 'Pending', 'Completed'),
)
Same for any other array key.
Note that some quick debugging of the array reveals this.
Please also see the tons of other stackoverflow questions with the same issue or other areas where basic research could have pointed you in this direction. Taking a look there first can help to resolve the issue in less time.

Categories