Warning: Invalid argument supplied for foreach() despite everything looking fine - php

I have an array that's being passed to a foreach and even though I've used foreach's hundred's of times before, I can't figure out why this is giving me the error, Warning: Invalid argument supplied for foreach()
switch($searchby){
case 0: // Name
print_r($data);
foreach($data as $key => $i){
if($key % 2 == 0 && $i == $searchfor){
$success = TRUE;
$matches[] = array('name' => $i, 'value' => $data[$key+1]);
}
}
break;
}
The print_r prints a normal array, for instance (an actual example):
Array
(
[0] => Username
[1] => 4567
[2] => Password
[3] => 4567
[4] => Name
[5] => 4567
[6] => Age
[7] => 4567
[8] => Country
[9] => 4567
[10] => Type
[11] => Register
)
---- Since apparently it works, here's the entire callstack with the stack marked with <------: ----
/// Main.js ///
$("form#Register").submit(function () {
event.preventDefault();
$.post("php/proc.php",{'Command':'registerUser','Data':$(this).serialize()},function (data) { // <---- Original call
console.log(data);
});
return false;
});
// proc.php //
echo json_encode($MainLib->registerUser($db, $data)); // <--------- #1
class MainLib
{
public function registerUser($db, $data){
$pword = $this->hashpword($db, $result1[0]['value'], $result2[0]['value'], 'Register'); // <---------------- #2
}
public function hashpword($db, $data){
$uname = $this->searchData(0,'Username',$data); // <----------- #3
$pword = $this->searchData(0,'Password',$data);
$type = $this->searchData(0,'Type',$data);
switch($type){
case 'Register':
$salt = uniqid(rand(0,99999999),TRUE);
$db->query("UPDATE `Users` SET `salt`='" . $salt . "' WHERE `Username`='" . $uname . "'");
echo "UPDATE `Users` SET `salt`='" . $salt . "' WHERE `Username`='" . $uname . "'";
break;
$result = $db->query("SELECT * FROM `Users` WHERE `Username`='" . $uname . "'");
while($row = $result->fetch_assoc()){
$salt = $row['salt'];
}
}
$salt = base_convert($salt, 26, 10);
$pword = base_convert($pword, 26, 10);
$new_pword = $pword * $salt;
$new_pword = base_convert($new_pword, 10, 17);
$pword = hash('sha512',$new_pword);
return $pword;
}
public function searchData($searchby, $searchfor, $data){
$success = FALSE;
switch($searchby){
case 0: // Name
print_r($data);
foreach($data as $key => $i){ // <--------- ERROR
if($key % 2 == 0 && $i == $searchfor){
$success = TRUE;
$matches[] = array('name' => $i, 'value' => $data[$key+1]);
}
}
break;
case 1: // Value
foreach($data as $key => $i){
if($key % 2 == 0 && $data[$key+1] == $searchfor){
$success = TRUE;
$matches[] = array('name' => $i, 'value' => $data[$key+1]);
}
}
break;
}
if($success) return $matches;
return FALSE;
}
}

this might not be the right answer, i just want to know if this will suppress the error:
switch($searchby){
case 0: // Name
if(is_array($data)) { //--> add this validation
print_r($data);
foreach($data as $key => $i){
if($key % 2 == 0 && $i == $searchfor){
$success = TRUE;
$matches[] = array('name' => $i, 'value' => $data[$key+1]);
}
}
} else {
die('Invalid Array!');
}
break;
}
try to add is_array condition if it could still print the value of $data and able to continue your script.

Related

How to set the index value as 0 for the array in php?

I am working on my php to fetch the data to store them in an array. I have got a problem with the index value in the array, because the index value will start with 1 then it will count it up to 2, 3, 4...etc which it should start with 0 then 1, 2 3...etc, because I am using $i = 0; to start with zero as default.
Here is what I use that the index value start with 1:
if(isset($structure->parts) && count($structure->parts)) {
for($i = 0; $i < count($structure->parts); $i++) {
if (($structure->parts[$i]->ifdisposition) && ($structure->parts[$i]->disposition == 'attachment')) {
foreach($structure->parts[$i]->parameters as $object) {
if(strtolower($object->attribute) == 'name') {
$attachments[$i]['is_attachment'] = true;
$attachments[$i]['name'] = $object->value;
$attachments[$i]['attachment'] = '';
}
}
}
}
I have tried to change from $i++ to $i and I tried to put $i++ in the for loop, but it didn't work.
Output:
Array ( [1] => Array ( [is_attachment] => 1 [name] => 2019-01-23 (1).rar [attachment] => ) [2] => Array ( [is_attachment] => 1 [name] => email.zip [attachment] => ) )
It should be:
Array ( [0] => Array ( [is_attachment] => 1 [name] => 2019-01-23 (1).rar [attachment] => ) [1] => Array ( [is_attachment] => 1 [name] => email.zip [attachment] => ) )
Here is the full code:
<?php
require_once "Mail.php";
require_once('Mail/IMAPv2.php');
$username = 'username';
$password = 'password';
$mailserver = '{imap.domain.com:993/imap/ssl/novalidate-cert}INBOX';
$mailbox = imap_open($mailserver, $username, $password) or die("Can't connect: " . imap_last_error());
$key = "key";
$email_number = openssl_decrypt(hex2bin('477'),'AES-128-CBC', $key);
$attach_id = $_GET['attid'];
/* get information specific to this email */
$overview = imap_fetch_overview($mailbox, $email_number, 0);
$message = imap_fetchbody($mailbox, $email_number, 2);
/* get mail structure */
$structure = imap_fetchstructure($mailbox, $email_number);
$attachments = array();
$attachment_number = 0;
if(isset($structure->parts) && count($structure->parts)) {
for($i = 0; $i < count($structure->parts); $i++) {
if (($structure->parts[$i]->ifdisposition) && ($structure->parts[$i]->disposition == 'attachment')) {
foreach($structure->parts[$i]->parameters as $object) {
if(strtolower($object->attribute) == 'name') {
$attachments[$i]['is_attachment'] = true;
$attachments[$i]['name'] = $object->value;
$attachments[$i]['attachment'] = '';
}
}
}
}
?>
I am unable to find out why the index value have always start with 1 when it should have start with zero then 1, 2, 3 as it get counting up the value each time.
Can you please show me an example how I can start the index value with 0 as a default then count it up to 1, then 2, 3, 4, 5...etc when I am using $i++?
Thank you.
It's because $structure->parts[0] does not match $structure->parts[$i]->disposition == 'attachment' in all cases.
Only create a new item in your array when one is correct and dont use the loop counter use a simpe $arr[] contruct to create the next occurance
$attachments = array();
if(isset($structure->parts) && count($structure->parts)) {
foreach ($structure->parts as $part) {
if (($part->ifdisposition) && ($part->disposition == 'attachment')) {
foreach($part->parameters as $obj) {
if(strtolower($obj->attribute) == 'name') {
$t['is_attachment'] = true;
$t['name'] = $obj->value;
$t['attachment'] = '';
$attachments[] = $t
}
}
}
}
}
Try this
foreach($structure->parts[$i]->parameters as $object) {
if(strtolower($object->attribute) == 'name') {
$attachment['is_attachment'] = true;
$attachment['name'] = $object->value;
$attachment['attachment'] = '';
$attachments[]=$attachment;
}
}
If you want to know why indexes of array start with 1 and not 0, show us definition of array.
But you can also loop array with unknown keys with for loop by getting array keys with PHP array_keys function
$this->arr = [1 => 'one', 2 => 'two', 3 => 'three'];
$keys = array_keys($this->arr);
for($i = 0; $i < count($keys); $i++) {
$value = $this->arr[$keys[$i]];
echo 'val: ' .$value.'<br>';
}
Or you can wrap two foreaches into another
foreach($structure->parts as $key => $part){
$part->ifdisposition = true;
$part->disposition = 'attachment';
if (($part->ifdisposition) && ($part->disposition == 'attachment')) {
foreach($part->parameters as $object) {
if(strtolower($object->attribute) == 'name') {
$attachments[$key]['is_attachment'] = true;
$attachments[$key]['name'] = $object->value;
$attachments[$key]['attachment'] = '';
}
}
}
}
Another option is to remap keys of array, using array_map but you array will be altered, so if you need the original array, you can cache it into another variable.
Here:
$attachments[$i]['is_attachment'] = true;
$attachments[$i]['name'] = $object->value;
$attachments[$i]['attachment'] = '';
You are setting the key to $i, so the first element in $structure->parts to match the criteria is the second element in the loop. To set the $attachments array starting at zero, you simply need to let PHP create the keys itself:
$attachments[] = ['is_attachment' => true, 'name' => $object->value, 'attachment' => ''];

How can I return a PHP $_POST array as string that is usable as a name attribute?

Question:
I have an array of post values that looks like:
$_POST['children'] = array(
[0]=>array(
'fname' => 'name',
'mname' => 'mname',
'lname' => 'lname,
'dob' => '10/17/1992
),
[1]=>array(
'fname' => 'name',
'mname' => 'mname',
'lname' => 'lname,
'dob' => '10/17/1992
),
[2]=>array(
'fname' => 'name',
'mname' => 'mname',
'lname' => 'lname,
'dob' => '10/17/1992
)
);
// and so on
I have a script set up in my my view functions that checks for old input, and repopulates the values in the case that the form does not validate. I need to find a way to return the above array as a series of key/value pairs i.e.
'children[0][fname]' = 'name'
'children[0][mname]' = 'mname'
'children[0][lname]' = 'lname'
// ... and so on for all fields
Ideally, I would like this to work with an array of any depth, which makes me think I need some sort of recursive function to format the keys. I am having a terrible time getting my head around how to do this.
What I have tried
I have been working with the following function:
function flatten($post_data, $prefix = '') {
$result = array();
foreach($post_data as $key => $value) {
if(is_array($value)) {
if($prefix == ''){
$result = $result + flatten($value, $prefix. $key );
}else{
$result = $result + flatten($value, $prefix. '[' . $key . ']');
}
}
else {
$result[$prefix . $key .''] = $value;
}
}
return $result;
}
This gets me somewhat close, but isn't quite right. It returns the following when I feed it my $_POST array
[children[1]fname] => test
[children[1]mname] => test
[children[1]lname] => test
[children[1]dob] =>
// Expecting: children[1][fname] => test
// ...
Or is there potentially an easier way to accomplish this?
What ended up working for me:
function flatten($post_data, $prefix = '') {
$result = array();
foreach($post_data as $key => $value) {
if(is_array($value)) {
if($prefix == ''){
$result = $result + flatten($value, $prefix. $key );
}else{
$result = $result + flatten($value, $prefix. '[' . $key . ']');
}
}
else {
if( $prefix == ''){
$result[$prefix . $key.''] = $value;
}else{
$result[$prefix . '['.$key.']'.''] = $value;
}
}
}
return $result;
}
it wasn't accounting for the return value of the last call of the recursive function being a scalar value. The addition of these this if/else statement seems to have resolved it.
if( $prefix == ''){
$result[$prefix . $key.''] = $value;
}else{
$result[$prefix . '['.$key.']'.''] = $value;
}

PHP Read Specific Value from API Response

I have this bit of code:
<?php
#
# Sample Socket I/O to CGMiner API
#
function getsock($addr, $port)
{
$socket = null;
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket === false || $socket === null)
{
$error = socket_strerror(socket_last_error());
$msg = "socket create(TCP) failed";
echo "ERR: $msg '$error'\n";
return null;
}
$res = socket_connect($socket, $addr, $port);
if ($res === false)
{
$error = socket_strerror(socket_last_error());
$msg = "socket connect($addr,$port) failed";
echo "ERR: $msg '$error'\n";
socket_close($socket);
return null;
}
return $socket;
}
#
# Slow ...
function readsockline($socket)
{
$line = '';
while (true)
{
$byte = socket_read($socket, 1);
if ($byte === false || $byte === '')
break;
if ($byte === "\0")
break;
$line .= $byte;
}
return $line;
}
#
function request($cmd)
{
$socket = getsock('127.0.0.1', 4028);
if ($socket != null)
{
socket_write($socket, $cmd, strlen($cmd));
$line = readsockline($socket);
socket_close($socket);
if (strlen($line) == 0)
{
echo "WARN: '$cmd' returned nothing\n";
return $line;
}
print "$cmd returned '$line'\n";
if (substr($line,0,1) == '{')
return json_decode($line, true);
$data = array();
$objs = explode('|', $line);
foreach ($objs as $obj)
{
if (strlen($obj) > 0)
{
$items = explode(',', $obj);
$item = $items[0];
$id = explode('=', $items[0], 2);
if (count($id) == 1 or !ctype_digit($id[1]))
$name = $id[0];
else
$name = $id[0].$id[1];
if (strlen($name) == 0)
$name = 'null';
if (isset($data[$name]))
{
$num = 1;
while (isset($data[$name.$num]))
$num++;
$name .= $num;
}
$counter = 0;
foreach ($items as $item)
{
$id = explode('=', $item, 2);
if (count($id) == 2)
$data[$name][$id[0]] = $id[1];
else
$data[$name][$counter] = $id[0];
$counter++;
}
}
}
return $data;
}
return null;
}
#
if (isset($argv) and count($argv) > 1)
$r = request($argv[1]);
else
$r = request('summary');
#
echo print_r($r, true)."\n";
#
?>
Which outputs this information:
summary returned 'STATUS=S,When=1399108671,Code=11,Msg=Summary,Description=cgminer 4.3.0hf|SUMMARY,Elapsed=531,MHS av=453052.33,MHS 5s=537024.44,MHS 1m=458922.01,MHS 5m=375184.88,MHS 15m=201623.38,Found Blocks=0,Getworks=16,Accepted=518,Rejected=12,Hardware Errors=271,Utility=58.54,Discarded=276,Stale=0,Get Failures=0,Local Work=65806,Remote Failures=0,Network Blocks=1,Total MH=240524241.0000,Work Utility=5589.33,Difficulty Accepted=49008.00000000,Difficulty Rejected=448.00000000,Difficulty Stale=0.00000000,Best Share=93465,Device Hardware%=0.5450,Device Rejected%=0.9059,Pool Rejected%=0.9059,Pool Stale%=0.0000,Last getwork=1399108671|'
Array
(
[STATUS] => Array
(
[STATUS] => S
[When] => 1399108671
[Code] => 11
[Msg] => Summary
[Description] => cgminer 4.3.0
)
[SUMMARY] => Array
(
[0] => SUMMARY
[Elapsed] => 531
[MHS av] => 453052.33
[MHS 5s] => 537024.44
[MHS 1m] => 458922.01
[MHS 5m] => 375184.88
[MHS 15m] => 201623.38
[Found Blocks] => 0
[Getworks] => 16
[Accepted] => 518
[Rejected] => 12
[Hardware Errors] => 271
[Utility] => 58.54
[Discarded] => 276
[Stale] => 0
[Get Failures] => 0
[Local Work] => 65806
[Remote Failures] => 0
[Network Blocks] => 1
[Total MH] => 240524241.0000
[Work Utility] => 5589.33
[Difficulty Accepted] => 49008.00000000
[Difficulty Rejected] => 448.00000000
[Difficulty Stale] => 0.00000000
[Best Share] => 93465
[Device Hardware%] => 0.5450
[Device Rejected%] => 0.9059
[Pool Rejected%] => 0.9059
[Pool Stale%] => 0.0000
[Last getwork] => 1399108671
)
)
How can I get a specific value? For example, how can I output only '[MHS 15m]'
if $res is the variable containing the array you can get the value as
echo $res['SUMMARY']['MHS 15m'];

Is there something like keypath in an associative array in PHP?

I want to dissect an array like this:
[
"ID",
"UUID",
"pushNotifications.sent",
"campaigns.boundDate",
"campaigns.endDate",
"campaigns.pushMessages.sentDate",
"pushNotifications.tapped"
]
To a format like this:
{
"ID" : 1,
"UUID" : 1,
"pushNotifications" :
{
"sent" : 1,
"tapped" : 1
},
"campaigns" :
{
"boundDate" : 1,
"endDate" : 1,
"pushMessages" :
{
"endDate" : 1
}
}
}
It would be great if I could just set a value on an associative array in a keypath-like manner:
//To achieve this:
$dissected['campaigns']['pushMessages']['sentDate'] = 1;
//By something like this:
$keypath = 'campaigns.pushMessages.sentDate';
$dissected{$keypath} = 1;
How to do this in PHP?
You can use :
$array = [
"ID",
"UUID",
"pushNotifications.sent",
"campaigns.boundDate",
"campaigns.endDate",
"campaigns.pushMessages.sentDate",
"pushNotifications.tapped"
];
// Build Data
$data = array();
foreach($array as $v) {
setValue($data, $v, 1);
}
// Get Value
echo getValue($data, "campaigns.pushMessages.sentDate"); // output 1
Function Used
function setValue(array &$data, $path, $value) {
$temp = &$data;
foreach(explode(".", $path) as $key) {
$temp = &$temp[$key];
}
$temp = $value;
}
function getValue($data, $path) {
$temp = $data;
foreach(explode(".", $path) as $ndx) {
$temp = isset($temp[$ndx]) ? $temp[$ndx] : null;
}
return $temp;
}
function keyset(&$arr, $keypath, $value = NULL)
{
$keys = explode('.', $keypath);
$current = &$arr;
while(count($keys))
{
$key = array_shift($keys);
if(!isset($current[$key]) && count($keys))
{
$current[$key] = array();
}
if(count($keys))
{
$current = &$current[$key];
}
}
$current[$key] = $value;
}
function keyget($arr, $keypath)
{
$keys = explode('.', $keypath);
$current = $arr;
foreach($keys as $key)
{
if(!isset($current[$key]))
{
return NULL;
}
$current = $current[$key];
}
return $current;
}
//Testing code:
$r = array();
header('content-type: text/plain; charset-utf8');
keyset($r, 'this.is.path', 39);
echo keyget($r, 'this.is.path');
var_dump($r);
It's a little rough, I can't guarantee it functions 100%.
Edit: At first you'd be tempted to try to use variable variables, but I've tried that in the past and it doesn't work, so you have to use functions to do it. This works with some limited tests. (And I just added a minor edit to remove an unnecessary array assignment.)
In the meanwhile, I came up with (another) solution:
private function setValueForKeyPath(&$array, $value, $keyPath)
{
$keys = explode(".", $keyPath, 2);
$firstKey = $keys[0];
$remainingKeys = (count($keys) == 2) ? $keys[1] : null;
$isLeaf = ($remainingKeys == null);
if ($isLeaf)
$array[$firstKey] = $value;
else
$this->setValueForKeyPath($array[$firstKey], $value, $remainingKeys);
}
Sorry for the "long" namings, I came from the Objective-C world. :)
So calling this on each keyPath, it actually gives me the output:
fields
Array
(
[0] => ID
[1] => UUID
[2] => pushNotifications.sent
[3] => campaigns.boundDate
[4] => campaigns.endDate
[5] => campaigns.pushMessages.endDate
[6] => pushNotifications.tapped
)
dissectedFields
Array
(
[ID] => 1
[UUID] => 1
[pushNotifications] => Array
(
[sent] => 1
[tapped] => 1
)
[campaigns] => Array
(
[boundDate] => 1
[endDate] => 1
[pushMessages] => Array
(
[endDate] => 1
)
)
)

(PHP) values of an array - recursion

After hours going around in circles I gave up and ask for help.
I have an array which looks like:
[field01] => Array
(
[name] => test01
[prefix] => C01
)
[field02] => Array
(
[url] => http://www.url.com
[user] => a_user
[password] => a_password
)
[filed03] => Array
(
[0] => Array
(
[id] => 1
[Type] => standard
[Name] => name
)
[1] => Array
(
[id] => 5
[Type] => standard
[Name] => name
)
)
Now I want to go through that array and get the following output as a return from a recursive function:
Array (
[0] = "The values of field01: name, prefix - test01, C01"
[1] = "The values of field02: url, user, password - http://www.url.com, a_user, a_password"
[2] = "The values of field03: id, Type, Name - 1, standard, name"
[3] = "The values of field03: id, Type, Name - 5, standard, name"
)
I have tried it with a recursive function but stuck with field03 to save the name.
Any help for that?
UPDTAE:
here is the array, so you don't have to write it:
$data['field01']['name'] = "field01";
$data['field01']['prefix'] = "C01";
$data['field02']['url'] = "http://www.url.com";
$data['field02']['user'] = "a_user";
$data['field02']['password'] = "a_password";
$data['field03'][0]['List_id'] = 1;
$data['field03'][0]['Type'] = "standard";
$data['field03'][0]['Name'] = "name";
$data['field03'][1]['List_id'] = 5;
$data['field03'][1]['Type'] = "standard";
$data['field03'][1]['Name'] = "name";
Thanks in advance!
<?php
$data['field01']['name'] = "field01";
$data['field01']['prefix'] = "C01";
$data['field02']['url'] = "http://www.url.com";
$data['field02']['user'] = "a_user";
$data['field02']['password'] = "a_password";
$data['field03'][0]['List_id'] = 1;
$data['field03'][0]['Type'] = "standard";
$data['field03'][0]['Name'] = "name";
$data['field03'][1]['List_id'] = 5;
$data['field03'][1]['Type'] = "standard";
$data['field03'][1]['Name'] = "name";
$text = '';
foreach ($data as $k => $fields) {
if (isset($fields[0])) {
foreach ($fields as $field) {
$text .= 'The values of ' . $k . ': ' . traverse($field) . "\n";
}
} else {
$text .= 'The values of ' . $k . ': ' . traverse($fields) . "\n";
}
}
echo $text;
function traverse($fields) {
$keys = array_keys($fields);
$values = array_values($fields);
return implode(', ', $keys) . ' - ' . implode(', ', $values);
}
?>
This assumes if there is an array of arrays, it is all arrays. In other words, you aren't mixing strings with arrays.
$resultArray = array();
function process($inputArray, $fieldName) {
$result = array();
$keys = array_keys($inputArray);
if (!is_array($inputArray[0])) {
$result[] = "The value of $fieldName: ".implode($keys,', '). ' - '. implode($inputArray, ', ');
} else {
foreach($inputArray as $arr) {
$result = array_merge($result, process($arr, $fieldName));
}
}
return $result;
}
foreach($data as $k=>$v) {
$processed = process($v, $k);
$resultArray = array_merge($resultArray, $processed);
}
print_r($resultArray);

Categories