I have a project that uses MSSQL over pdo_dblib and freetds. MS scalar functions always returned their data in this format:
array(1) { [0]=> array(1) { ["computed"]=> string(3) "922" } }.
But now, on one of the servers the format suddenly is:
array(1) { [0]=> array(1) { [""]=> string(3) "922" } }.
So the key in the array became empty instead of "computed".
I know that I can change that key in my select statements by adding "as" clause. Still, the question is, what controls the default key?
Both servers use the same database.
As far as I know, this "computed" key is something that's added by pdo_dblib.
PHP version is different between servers, the one with computed has old 5.3, while the one with empty key has 5.5. But I think that this server had 5.5 for quite some time, while the computed key disappeared just yesterday. Not 100% sure though...
In the end I found out that this happens because there was a change in this commit to pdo_dblib. The motivation for this change was that it was clogging up memory.
It should be noted that the version that you get from pecl is weird. It has "computed" in dblib_stmt.c source, but still does not use it.
The version that works, is the one bundled with php sources. I was able to take sources from php-5.3.29\ext\pdo_dblib\ and build them against 5.6.4.
Related
This isn't really a surprise that function implementations change sometimes from version to version, but not like this... Look:
$array = ["abc","def"];
$object = new stdclass();
foreach($array as $index => $value) {
$object->$index = $value;
}
var_dump(get_object_vars($object));
For 5.6.x and then e.g. 7.0.17 and 7.1.3 we get:
array(2) {
[0]=> string(3) "abc"
[1]=> string(3) "def"
}
But for 7.0.0 and 7.0.16 and 7.1.0 we get:
array(2) {
["0"]=> string(3) "abc"
["1"]=> string(3) "def"
}
demo: https://3v4l.org/jog4A
See? The keys are integers OR strings, depending on version.
Why? What is the reasoning behind those changes? And why isn't this documented anywhere? Or... is it?
If you look more closely at the versions on that 3v4.org output, it was broken in 7.0.0 up to and including 7.0.16, and 7.1.0 up to and including 7.1.2. So this was a bug introduced in 7.0, and fixed on both active releases in time for 7.0.17 and 7.1.3 (both release March 16 2017).
Looking at the PHP changelog we can see a relevant looking entry:
Fixed bug #73998 (array_key_exists fails on arrays created by get_object_vars).
This leads us to the bug tracker, and from there to commit dd9cf23457e21d2bda29dc92d437b9dbd14027b2 in th git repo:
BUG #73998: Numeric properties are not accessible from get_object_vars
The fix involves adding a check for if there are numeric keys present, and skipping a block labelled "fast_copy" if there are.
So this was an undesired side-effect of a performance optimisation made during the development of PHP 7, and has now been fixed in all supported releases.
Interestingly, Andrea commented on the bug report that it is closely related to an RFC to change the behaviour of object-to-array casts which describes the general problem:
Because arrays and objects have different restrictions versus the underlying HashTable type on what kinds of keys they can have, the Zend Engine must enforce their restrictions at a layer above HashTables, in the code implementing arrays and objects themselves. This means that if that code is bypassed and the underlying HashTables are modified directly, arrays and objects can exist with an invalid internal state.
And the specific case addressed by the RFC:
For example, $arr = [0 => 1, 1 => 2, 2 => 3]; $obj = (object)$arr; produces an object with inaccessible properties named , 1 and 2, while $obj = new stdClass; $obj->{'0'} = 1; $obj->{'1'} = 2; $obj->{'2'} = 3; produces an array with the inaccessible keys "0", "1" and "2". The same issue also occurs when using get_object_vars().
The RFC is implemented in 7.2.0, as it changes documented behaviour, but the behaviour of get_object_vars() was actually an inadvertent change in 7.0, so was implemented as a bug fix.
Actually it is a bug, because variables must start with letter.
Variable names follow the same rules as other labels in PHP. A valid
variable name starts with a letter or underscore, followed by any
number of letters, numbers, or underscores. As a regular expression,
it would be expressed thus: '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*'
http://php.net/manual/en/language.variables.basics.php
So when you are trying to set variables $object->$index = $value; it must throw an error (you cant set the variable like this $1 = 'foo'; or $obj->1 = 'foo';).
array(2) {
["0"]=> string(3) "abc"
["1"]=> string(3) "def"
}
Is a right result, because get_object_vars returns associative array.
Return Values ¶
Returns an associative array of defined object accessible non-static
properties for the specified object in scope. If a property has not
been assigned a value, it will be returned with a NULL value.
http://php.net/manual/en/function.get-object-vars.php
I have an issue, that is not necessarily in the scope of most questions asked here.
I have an application I am developing that checks a domain for certain A records and also tests ports on the resolving server to check if they are open and listening.
I have added functionality on my local copy of the site, but it is too slow for me to publish, come to think of it, so is the current published site.
You can see the app on the link: http://www.domainion.co.za
Enter a domain name (without www) and it will check for certain records.
This is a symfony app, I am getting these records by running multiple exec() statements with digs for specific information. The reason I like using exec, is because if there are multiple records returned, like the below command, it lets you assign each result to an index of an array.
dig -x 154.0.174.35 +short #8.8.8.8
motairgdiool.hosted.co.za. (index 0)
kent.aserv.co.za. (index 1)
Now, this is taking way too long (on average 8 seconds to load). My issue with this, is if you had to take all these commands in this app and run it in a shell script, they take under a second to run, I suspect the reason mine takes so long, is that PHP is opening and closing a virtual shell for each of these commands.
In an attempt to run these queries quicker, I have tried the below:
shell_exec() - This takes about the same time, and returns all results as a string, I can't use that.
proc_open - takes longer, also returns a long string.
symfony process() component - takes waaay longer and also returns all results as one string
dns_check_record() - you can't check for specific subdomain records
TLDR : Is there any way I can get records that i want (n.domain.tld) and still have the application run fast?
Thanks
$ php -r 'var_dump(dns_get_record("35.174.0.154.in-addr.arpa"));'
Returns the following in under a one fifth of a second, including invoking the PHP interpreter:
array(2) {
[0]=>
array(5) {
["host"]=>
string(25) "35.174.0.154.in-addr.arpa"
["class"]=>
string(2) "IN"
["ttl"]=>
int(7192)
["type"]=>
string(3) "PTR"
["target"]=>
string(16) "kent.aserv.co.za"
}
[1]=>
array(5) {
["host"]=>
string(25) "35.174.0.154.in-addr.arpa"
["class"]=>
string(2) "IN"
["ttl"]=>
int(7192)
["type"]=>
string(3) "PTR"
["target"]=>
string(25) "motairgdiool.hosted.co.za"
}
}
Use local DNS. It would be faster than a query to #8.8.8.8
dig -x 154.0.174.35 +short
After getting result from Sql query, I stored my result in a $data array, which after var_dump($data) looks somewhat like this:
array(100) {
[0]=>
object(stdClass)#3 (3) {
["qid"]=>
string(2) "19"
["q_no_on_paper"]=>
string(1) "0"
["question_text"]=>
string(139) " Consider the following statements- 1- The Centre recently unveiled the expanded version of the. . ."
}
[1]=>
object(stdClass)#4 (3) {
["qid"]=>
string(2) "16"
["q_no_on_paper"]=>
string(1) "0"
["question_text"]=>
string(138) ". There is dispute over the Tipaimukh hydraulic project between India and A. Bhutan B. Nepal C.. . ."
} ...
The array is long, so this is just a part of it.
Now when I do json_encode($data); , and then var_dump it, I get bool(false).
I tried to use json_last_error() after following the Example #1 in this PHP documentation link , it shows - No errors
Where am I going wrong? Why is it not encoding it?
EDIT:
The ["question_text"] contains some html text.
This may help you out,
Although this is not documented on the version log , non-UTF8 handling behavior has changed in 5.5, in a way that can make debugging difficult.
Passing a non UTF-8 string to json_encode() will make the function return false in PHP 5.5, while it will only nullify this string (and only this one) in previous versions.
In a Latin-1 encoded file, write this:
<?php
$a = array('é', 1);
var_dump(json_encode($a));
?>
PHP < 5.4:
string(8) "[null,1]"
PHP >= 5.5:
bool(false)
PHP 5.5 has it right of course (if encoding fails, return false) but its likely to introduce errors when updating to 5.5 because previously you could get the rest of the JSON even when one string was not in UTF8 (if this string wasn't used, you'd never notify it's nulled)
So you may encountered the later example of PHP >= 5.5
See at php.net documentation http://php.net/manual/en/function.json-encode.php#115733
I see some white space/HTML characters (like \n, \t, \r) in var_dump($data) result. This makes JSON invalid and hence json_encode returns false. Check the following index in your array...
["question_text"]=> string(139) " Consider the following statements-
I'm running a code getting data from a DB server, everything is working fine locally. But when I push it online, it's not working anymore.
I think I know where the problem comes from. Here is the data I get locally:
object(stdClass)#451 (14) {
["matter_created_actionstep_c"]=>
string(1) "1"
["trust_receipt_sent_c"]=>
string(1) "1"
["scope_complete_c"]=>
string(1) "0"
["transferred_trust_to_current_c"]=>
string(1) "0"
}
And when I push it on my server, here is the result I get:
object(stdClass)#451 (14) {
["matter_created_actionstep_c"]=>
int(1)
["trust_receipt_sent_c"]=>
int(1)
["scope_complete_c"]=>
int(0)
["transferred_trust_to_current_c"]=>
int(0)
}
Are you aware of any apache configuration that would lead to this typeset change?
The only project file that is different, is the conf file:
locally:
DB_HOST=1.1.1.1
on the server:
DB_HOST=localhost
Thanks in advance.
This can result from a lot of issues. Maybe a different PHP version, maybe the data comes from a database and the version of the database driver is different, …
I would say the application is to blame. PHP is untyped, meaning in most cases nobody cares for the actual type of a variable. In your case barely anybody cares if the value is 2 or "2" as long as it behaves the same (e.g. 2==2 equals 2=="2"). If the application requires certain types in some variables, it should assure the variables contain these types! This is not the case here.
Check the application and the part of the code which writes the value into the object. This part of code should cast the value to the desired type before putting it into the variable.
Nevertheless (or if the object comes from somewhere else) it may make sense to make the code more forgiving concerning types, i.e. do not rely on a special type as long as it is not necessary. In my experience there are only few cases when type of variables really matter.
Quoted from here:
If delimiter contains a value that is
not contained in string and a negative
limit is used, then an empty array
will be returned, otherwise an array
containing string will be returned.
But why I still don't get an empty array?
var_dump(explode(',', '', -1))
I get this:
array(1) {
[0]=>
string(0) ""
}
UPDATE
Try it in windows,with PHP 5.2.8 (cli) (built: Dec 8 2008 19:31:23)
I can confirm that this doesn't work in PHP 5.2.8.
It does work in PHP 5.2.11. In my opinion, there are many bugs in the 5.2 branch, so try always to use the latest version. 5.3 is more stable in my experience.
I've tried this example and got empty array. Wrong question.
Tested your code, and it does return an empty array: array(0) { }.
Running PHP 5.2.11.
Maybe there's an issue with your PHP version. Can you tell us which one you are running?