Mantis - Quercus
Viewing Issue Advanced Details
4059 block always 06-01-10 09:13 06-08-10 08:26
sblommers Linux  
Ubuntu  
normal 10.04  
new 4.0.8  
SVN open  
none    
none  
0004059: PHP Type comparison not the same
Differences in type comparison between Quercus and PHP that are possibly causing most incompatibilities in existing PHP applications running on Quercus.

Some of the type checks that are different on Quercus are causing major inconsistencies in data (I filed some bugs for Drupal).
Run this script on both PHP and Quercus and see the difference (or download from https://streamconsulting.nl/drop/php-type-comparison.php) [^]

<?php

$tests = array();

/* Testing equalty */
$tests['=='] = create_function('$a, $b', 'return $a==$b;');
$tests['!='] = create_function('$a, $b', 'return $a!=$b;');
$tests['<>'] = create_function('$a, $b', 'return $a<>$b;');
$tests['<'] = create_function('$a, $b', 'return $a<$b;');
$tests['>'] = create_function('$a, $b', 'return $a>$b;');
$tests['<='] = create_function('$a, $b', 'return $a<=$b;');
$tests['>='] = create_function('$a, $b', 'return $a>=$b;');
/* Testing identity */
$tests['==='] = create_function('$a, $b', 'return $a===$b;');
$tests['!=='] = create_function('$a, $b', 'return $a!==$b;');

$comparison = array();
$comparison['TRUE'] = true;
$comparison['FALSE'] = false;
$comparison['1'] = 1;
$comparison['0'] = 0;
$comparison['-1'] = -1;
$comparison['3,14'] = pi();
$comparison['"1"'] = '1';
$comparison['"0"'] = '0';
$comparison['"-1"'] = '-1';
$comparison['NULL'] = null;
$comparison['array()'] = array();
$comparison['"php"'] = 'php';
        
print '<h1>PHP version '.PHP_VERSION.' type comparison tables</h1>';

foreach ($tests as $test=>$function) {
    print "<h2>Comparisons with $test</h2>";
    print "<table border='1'>";
    print "<tr>";
    print "<th>&nbsp;</th>";
    foreach (array_keys($comparison) as $name) {
        print "<th>$name</th>";
    }
    print "</tr>";
    foreach ($comparison as $arg_1_name => $arg_1_value) {
        print '<tr>';
        print "<th>$arg_1_name</th>";
        foreach ($comparison as $arg_2_value) {
            print '<td>';
            print $function($arg_1_value, $arg_2_value)==true ?
                        '<span style="color:00F;">TRUE</span>' : '<span style="color:#F00;">FALSE</span>';
            print '</td>';
        }
        print "</tr>";
    }
    print "</table>";
}
?>

Notes
(0004635)
sblommers   
06-08-10 08:26   
It took me some time but I managed to workaround every incorrect comparison and created a diff. https://streamconsulting.nl/drop/Value_TypeChecking_4059.diff [^]

diff -r 9ce0fb81b2de modules/quercus/src/com/caucho/quercus/env/ArrayValue.java
--- a/modules/quercus/src/com/caucho/quercus/env/ArrayValue.java Fri Jun 04 10:57:18 2010 +0200
+++ b/modules/quercus/src/com/caucho/quercus/env/ArrayValue.java Tue Jun 08 17:23:30 2010 +0200
@@ -613,13 +613,25 @@
     // arrays are uncomparable, otherwise - compare value by value"
 
     // php/335h
+
+ if (rValue.isBoolean() || rValue.isNull()) {
+ boolean lBool = toBoolean();
+ boolean rBool = rValue.toBoolean();
 
- if (!rValue.isArray())
- return 1;
+ if (! lBool && rBool)
+ return -1;
+ if (lBool && ! rBool)
+ return 1;
 
- int lSize = getSize();
+ return 0;
+ }
+
+ if(!rValue.isArray())
+ return 1;
+
+ int lSize = getSize();
     int rSize = rValue.toArray().getSize();
-
+
     if (lSize != rSize)
       return lSize < rSize ? -1 : 1;
 
@@ -1419,8 +1431,16 @@
       return false;
 
     final Set<Map.Entry<Value,Value>> entryset = entrySet();
+
     if (rValue instanceof BooleanValue)
- return entryset.size() > 0 ? rValue.toBoolean() : !rValue.toBoolean();
+ return !entryset.isEmpty() ? rValue.toBoolean() : !rValue.toBoolean();
+
+ if(rValue instanceof ArrayValueImpl && entryset.isEmpty()) {
+ final Set<Map.Entry<Value,Value>> rentryset = ((ArrayValueImpl)rValue).entrySet();
+ if(rentryset.size() > 0)
+ return false;
+ else return true;
+ }
 
     for (Map.Entry<Value, Value> entry: entryset) {
       Value entryValue = entry.getValue();
diff -r 9ce0fb81b2de modules/quercus/src/com/caucho/quercus/env/BooleanValue.java
--- a/modules/quercus/src/com/caucho/quercus/env/BooleanValue.java Fri Jun 04 10:57:18 2010 +0200
+++ b/modules/quercus/src/com/caucho/quercus/env/BooleanValue.java Tue Jun 08 17:23:30 2010 +0200
@@ -262,7 +262,7 @@
   public int cmp(Value rValue)
   {
     boolean rBool = rValue.toBoolean();
-
+
     if (! _value && rBool)
       return -1;
     if (_value && ! rBool)
diff -r 9ce0fb81b2de modules/quercus/src/com/caucho/quercus/env/LongValue.java
--- a/modules/quercus/src/com/caucho/quercus/env/LongValue.java Fri Jun 04 10:57:18 2010 +0200
+++ b/modules/quercus/src/com/caucho/quercus/env/LongValue.java Tue Jun 08 17:23:30 2010 +0200
@@ -452,7 +452,7 @@
   @Override
   public int cmp(Value rValue)
   {
- if (rValue.isBoolean()) {
+ if (rValue.isBoolean() || rValue.isNull()) {
       boolean lBool = toBoolean();
       boolean rBool = rValue.toBoolean();
 
@@ -463,7 +463,10 @@
 
       return 0;
     }
-
+
+ if(rValue.isArray())
+ return -1;
+
     long l = _value;
     double r = rValue.toDouble();
 
diff -r 9ce0fb81b2de modules/quercus/src/com/caucho/quercus/env/NullValue.java
--- a/modules/quercus/src/com/caucho/quercus/env/NullValue.java Fri Jun 04 10:57:18 2010 +0200
+++ b/modules/quercus/src/com/caucho/quercus/env/NullValue.java Tue Jun 08 17:23:30 2010 +0200
@@ -565,6 +565,9 @@
       double l = 0;
       double r = rValue.toDouble();
 
+ if(r <= 0)
+ return -1;
+
       if (l == r)
         return 0;
       else if (l < r)
diff -r 9ce0fb81b2de modules/quercus/src/com/caucho/quercus/env/NumberValue.java
--- a/modules/quercus/src/com/caucho/quercus/env/NumberValue.java Fri Jun 04 10:57:18 2010 +0200
+++ b/modules/quercus/src/com/caucho/quercus/env/NumberValue.java Tue Jun 08 17:23:30 2010 +0200
@@ -40,6 +40,9 @@
   @Override
   public int cmp(Value rValue)
   {
+ if(rValue.isArray())
+ return -1;
+
     if (rValue.isBoolean() || rValue.isNull()) {
       boolean lBool = toBoolean();
       boolean rBool = rValue.toBoolean();
diff -r 9ce0fb81b2de modules/quercus/src/com/caucho/quercus/env/StringValue.java
--- a/modules/quercus/src/com/caucho/quercus/env/StringValue.java Fri Jun 04 10:57:18 2010 +0200
+++ b/modules/quercus/src/com/caucho/quercus/env/StringValue.java Tue Jun 08 17:23:30 2010 +0200
@@ -384,9 +384,37 @@
    */
   public int cmp(Value rValue)
   {
- if (isNumberConvertible() || rValue.isNumberConvertible()) {
+ if(rValue instanceof NullValue)
+ return cmpString(StringValue.EMPTY);
+
+ if(rValue.isArray())
+ return -1;
+
+ if(rValue instanceof BooleanValue) {
+ boolean lBool = toBoolean();
+ boolean rBool = rValue.toBoolean();
+
+ if (!lBool && rBool) return -1;
+ if (lBool && !rBool) return 1;
+ return 0;
+ }
+
+ if (isNumberConvertible() || rValue.isNumberConvertible()) {
+
       double l = toDouble();
       double r = rValue.toDouble();
+
+ if((!rValue.isNumberConvertible() && rValue instanceof ConstStringValue))
+ return -1;
+
+ if((!isNumberConvertible() && rValue instanceof ConstStringValue))
+ return 1;
+
+ if(!isNumberConvertible() && l > 0)
+ return 1;
+
+ if(l < 0 && (rValue instanceof NullValue || rValue instanceof BooleanValue))
+ return 1;
 
       if (l == r)
         return 0;