"Cannot use a scalar value as an array" for undefined values - php

I have the following piece of code:
function Biz_GetAccountsPerMarket($site = "", $cache = true){
if($site == ""){
$site = $_SESSION["sitedirect_current_site"];
}
$aAccounts = Sys_OptionsGet("sys_site/".$site, "account", $cache);
$aAccountInfo = array();
$aVatAccount = Biz_GetVatAccounts($site, $cache);
$aSalesAccount = Biz_GetSalesAccounts($site, $cache);
foreach((array)$aAccounts as $code => $data){
foreach((array)$data["data"] as $market => $aItem){
$aAccountInfo[$market][$code] = $aItem;
$aAccountInfo[$market][$code]["vat"] = $aVatAccount[$aItem["vat_account_code"]]["value"];
$aAccountInfo[$market][$code]["vat_account"] = $aVatAccount[$aItem["vat_account_code"]]["account"];
$aAccountInfo[$market][$code]["sales_account"] = $aSalesAccount[$aItem["sales_account_code"]]["account"];
}
}
return $aAccountInfo;
}
The four innermost lines in the nested loop generates warnings: "Cannot use a scalar value as an array".
Adding lines that initialises $aAccountInfo[$market] and $aAccountInfo[$market][$code] to empty arrays first silences the errors, but this is far from the only place in our code where nested arrays are initialised in this way; and I can't figure out why it is a problem in the first place.
The following code should reproduce the problem; as far as I can tell; but doesn't:
<?php
ini_set('display_errors', '1');
error_reporting(E_ALL | E_STRICT);
$aTest = [];
$aTest['key']['key'] = 'sausage';
If $aItem was a string or false, or any scalar; I could understand what the problem is; but then the warning should only happen for the last three lines, not all four.
There are other weird things happening there, I hope they're all connected. This is the only one I've managed to isolate enough to ask a question about.
Is it possble to set the default value created by array access somehow?
edit:
I've noticed that many strings that are generates have an extraneous "0". This breaks things, like SQL. If empty array values somehow default to "0" or something, that would explain a lot. I have no idea how that could happen though. I'm currently grepping for "register_tick_function"...

You need to check if arrays have the expected keys. Something like this:
$aAccountInfo[$market][$code]["vat"] = isset($aItem["vat_account_code"]) ? (isset($aVatAccount[$aItem["vat_account_code"]]) ? $aVatAccount[$aItem["vat_account_code"]]["value"] : []) : [];

I am afraid your code is wrong
This line
$aAccountInfo[$market][$code] = $aItem;
creates the new occurance containing a SCALAR value and you then try and add a sub array onto that scalar value, hence the error
If you do this instead
$t = array();
$t['item'] = $aItem;
$t["vat"] = $aVatAccount[$aItem["vat_account_code"]]["value"];
$t["vat_account"] = $aVatAccount[$aItem["vat_account_code"]]["account"];
$t["sales_account"] = $aSalesAccount[$aItem["sales_account_code"]]["account"];
$aAccountInfo[$market][$code] = $t;
Then you will get a sub array created with all the values in it;

Related

One liner to get a reference on a property, and initialize it if it doesn't exist

I'm used to JavaScript where I often write things like this: const ref = obj.arr || (obj.arr = []);.
With one line of code, this gives me a reference on obj.arr after having initialized it to empty array if it didn't exist.
I'm trying to do the same in PHP but I'm struggling with ampersands, since the assignation is done by copy of value by default. Here is my failing attempt which I thought it would work:
$ref= &$obj['arr'] ?? &($obj['arr'] = []);
If I understand your question correctly, a ternary operator should suffice:
$obj['arr'] = isset($obj['arr']) ? $obj['arr'] : [];
$ref = &$obj['arr']);

PHP super weird warning : illigal string offset while creating a key

I have a very strange problem.
I am running through a foreach loop to compile an array but I receive an error.
I reveive the following warning :
Warning: Illegal string offset 'clientaccount_id' in
For this line of code:
$this->PreparedData[$table][$field] = 0;
I would say this to be logic if I would be doing something like:
$testVariable = $this->PreparedData[$table][$field];
Then the variable $field filled with 'clientaccount_id' would not exist.
But I am CREATING the field 'clientaccount_id' so to ME this is almost impossible to give an error.
The code
private function AssignData(){
foreach($this->FieldKeys as $table => $value){
///######## IF THE PREPARED DATA ARRAY DOES NOT EXIST
if(isset($this->PreparedData[$table]) === false){
///######## SET THE ARRAY KEY
$this->PreparedData[$table] = array();
}
///######## RUN THROUGH ALL SET SUB DATA
foreach($value as $field){
///######## IF THE FIELD EXISTS
if(isset($this->AccountData[$field]) === true){
///######## ASSIGN THE DATA
///$this->PreparedData[$table][$field] = $this->AccountData[$field];
///$this->PreparedData[$field] = $this->AccountData[$field];
$this->PreparedData[$table][$field] = 0;
}
}
}
exit('GOT THROUGH!!');
}
Could anyone see the error I am overlooking?
Solved!!
Thanks to VMcreator
Changed :
isset($this->PreparedData[$table]) === false
to this:
is_array($this->PreparedData[$table]) === false
Please read the explanation below WHY
Try to change this line:
isset($this->PreparedData[$table]) === false
to this:
!is_array($this->PreparedData[$table])
I saw this explanation here:
It just boils down to PHP's crazy type system.
$fruits['response']['errormessage'] is the string 'banana', so you're
attempting to access a character in that string by the ['orange']
index.
The string 'orange' is converted to an integer for the purposes of
indexing, so it becomes 0, as in
$fruits['response']['errormessage'][0]. The 0th index of a string is
the first character of the string, so for non-empty strings it's
essentially set. Thus isset() returns true.
You might be curious why your situation is comparable to that quoted statement even if $this->PreparedData[$table] seems a single dimensional array only, well its not a single dimensional array only, because you are accessing a class object, its just like doing this $this["PreparedData"][$table].

compact() not adding empty variables

Im trying to get a list of variables into an array (for an error reporting class), but if the variable is NOT set it is not being "compacted".
The below is extracts of the code:
$testVar1 = 123;
$testVar2 = 'ABC';
$ErrorArray = compact('testVar1', 'testVar2', 'notSetVar');
I then walk through the $ErrorArray with :
foreach($ErrorArray as $key => $value) {
$TempErrorMessage .= '$'.$key.' == '.$value.' ---- ';
}
The resulting output is :
$testVar1 == 123 ---- $testVar2 == ABC ----
The problem is, i would like to to output "notSetVar" as ""/NULL, as this is likely to be where my error is....
Any suggestions would be greatly welcomed!
Best Regards
Ford
According to PHP doc
http://php.net/manual/en/function.compact.php
compact creates an array containing variables and their values.
For each of these, compact() looks for a variable with that name in the current symbol table and adds it to the output array such that the variable name becomes the key and the contents of the variable become the value for that key. In short, it does the opposite of extract().
Any strings that are not set will simply be skipped.
So, it is not possible to pass variable via compact unless its set. My suggestion is, check variable before compact().
$testVar1 = 123;
$testVar2 = 'ABC';
if (!isset($notSetVar) {
$notSetVar = null;
}
$ErrorArray = compact('testVar1', 'testVar2', 'notSetVar');
var_dump($ErrorArray);

php session variable multidimensional associative array issue

I've looked around SO, but can't find an explanation to what is going on in my $_SESSION variables.
#ob_start();
$k=#ob_get_contents();
#ob_end_clean();
#session_start();
unset($s,$m);
$m1 = explode(" ", microtime());
$stime = $m1[1] + $m1[0];
echo $k;
$_SESSION['resendConfirmation']['function'] = 'resend';
$_SESSION['resendConfirmation']['id'] = '8';
print_r($_SESSION);
outputs:
Array ( [resendConfirmation] => 8esend )
Why is it string replacing? I've never had this issue before.
What I want is thus:
Array([resendConfirmation] => Array(
[id] =>8
[function} => resend
)
)
I've never had this happen before, I'm totally confused!
UPDATE
In response to #DanRedux I've changed to two non-existent variable names to take the referencing out of the equation, still the same result...
$_SESSION['resendConfirmation']['tweak'] = 'resend';
$_SESSION['resendConfirmation']['tweak2'] = '8';
Same result :(
Did a sitewide query of resendConfirmation and none were found, but once I change that array name, it all worked, baffled, but fixed...
$_SESSION['reConfirm']['function'] = 'resend';
$_SESSION['reConfirm']['id'] = '8';
print_r($_SESSION);
Since I dont really know what other sorts of shenanigans the code is up to outside of this block you gave us I would say to just try this instead:
$_SESSION['resendConfirmation'] = array('id' => 8, 'function' => 'resend');
If this also fails then there has to be something else going on outside of what you posted. Good luck!
What you think is an multidimensional array really isn't. What really happens is:
What you think is an array is really a string. After that you are trying to access the string as an array. You are trying to access the element id which doesn't exists. PHP always tries to be smarter than it should and just says: OK I'll assume you meant the first index. So basically what happens is:
<?php
$notAnArray = 'somestring';
$notAnArray['id'] = '8';
var_dump($notAnArray); // 8omestring
This is the reason you should always enable error_reporting on your development machine:
error_reporting(E_ALL | E_STRICT);
ini_set("display_errors", 1);
And never suppress errors using #. Well there are some situations where you can use #, but this really isn't one of them.

Strange PHP string error

This is a very very weird bug that happens randomly. So I will try to explain this as best as I can. I'm trying to diminish the code substantially to pinpoint the problem without having to reference a framework, nor deal with 500 lines of code outside of the framework - so I will try and come back and update this question when I do. OK, so here we go.
So basically say I'm taking a string in a function and preg_replace like so:
$table = '/something';
print $table;
$table = preg_replace("#^(/)#",'prefix_',$table);
print $table;
The output will look something like
...
/something - prefix_something
/something - prefix_something
/something - /something
You have an error in you sql query... blah blah somewhere around SELECT * FROM /something
What happens is that after rolling through the code, this simply stops working and the sql errors out. What's more strange is that if I start commenting out code outside the function it then works. I put that code back in, it breaks.
I tried recoding this by substr($var,0,1) and var_dumping the variable. After a few rounds it returns a bool(false) value even though $var is in fact a string. It's very very strange. Has anybody run into this before? Is this a PHP bug? It's looking like it to me.
-- EDIT --
Example:
foreach ( $user as $id => $user ) {
get_data("/table_name","*", "user_id = '$id'");
}
#in the function $_table_ holds "/table_name"
$_table_ = trim($_table_);
$tmp = explode(',', $_table_);
$tables = array();
foreach ($tmp as $c => $n) {
$n = trim($n);
$a = substr($n, 0, 1);
$b = substr($n, 1);
if ($a == false) {
var_dump($n);
$a = substr($n, 0, 1);
var_dump($b);
var_dump($a);
}
if ($a == '/') { etc...
Output:
string(11) "/table_name" string(10) "table_name" bool(false)
If I switch to the original preg_replace functionality, it simply does not preg_replace and the same thing happens "/table_name" is return rather then "prefix_table_name" and this happens randomly. Meaning it will work on the string it broke on if I comment code out outside of the function that is seemingly unrelated.
--- SOLUTION ----
I found out that it has to do with string to array conversion in another function that caused this strange error.
Basically a function was expecting a null or array() value and instead a number was passed. We have notices turned off, so I turned them on and started fixing all the notices and warnings and that's how I found this strange bug. Now exactly what the inner workings are that created the problem is unknown to me. However I can define the symptom as a string assignment problem that would occur at some other place in the code which we caught when it wouldn't reassign the $table variable with the new preg_replace value which is detailed above. Now you know. The function looks something similar to this:
function format_something($one, $two, $three = array()){
if ($three['something'] == 'Y') {
/** etc... */
}
...
format_something('one','two',3);
After a while in a loop this type of conversion started having problems randomly in the code.
substr doesn't always return a string. If it can't find the substring, it returns false.
Return Values
Returns the extracted part of string, or FALSE on failure or an empty string.
You should test for this condition and var_dump the string you are searching to see what it contains in such cases.

Categories