Exemplo n.º 1
0
function customize_amt_schemaorg_metadata_content($metatags)
{
    $idx = -1;
    $mts = array_slice($metatags, 0);
    while (($i = find_property($mts, 'name', 'itemprop')) > -1) {
        $idx = $idx == -1 ? $i : $idx + $i + 1;
        $mts = array_slice($metatags, $idx + 1);
    }
    $contestID = get_query_var('contestID');
    $contestType = $_GET['type'];
    if (isset($contestID) && isset($contestType)) {
        $contest = get_contest_detail('', $contestID, $contestType);
        if (isset($contest)) {
            if ($idx == -1) {
                $metatags[] = '<meta itemprop="name" content="' . $contest->challengeName . '" />';
            } else {
                $metatags[$idx] = '<meta itemprop="name" content="' . $contest->challengeName . '" />';
            }
        }
    }
    return $metatags;
}
Exemplo n.º 2
0
function var_assign($file, $namespace, $ast, $current_scope, $current_class, &$vars)
{
    global $classes, $functions, $scope;
    $left = $ast->children[0];
    $right = $ast->children[1];
    $left_type = $right_type = null;
    $parent = $ast;
    $taint = false;
    // Deal with $a=$b=$c=1; and trickle the right-most value to the top through recursion
    if ($right instanceof \ast\Node && $right->kind == \ast\AST_ASSIGN) {
        $right_type = var_assign($file, $namespace, $right, $current_scope, $current_class, $vars);
    }
    if ($left instanceof \ast\Node && $left->kind != \ast\AST_VAR && $left->kind != \ast\AST_STATIC_PROP) {
        // Walk multi-level arrays and chained stuff
        // eg. $var->prop[1][2]->prop
        while ($left instanceof \ast\Node && $left->kind != \ast\AST_VAR) {
            $parent = $left;
            $left = $left->children[0];
        }
    }
    if ($left == null) {
        // No variable name for assignment??
        // This is generally for something like list(,$var) = [1,2]
        return $right_type;
    }
    if (!is_object($left)) {
        if ($left == "self") {
            // TODO: Looks like a self::$var assignment - do something smart here
            return $right_type;
        } else {
            if ($left == 'static') {
                // TODO: static::$prop assignment
                return $right_type;
            } else {
                return $right_type;
            }
        }
    } else {
        if ($left->kind == \ast\AST_LIST) {
            return '';
        }
    }
    // DEBUG
    if (!$left instanceof \ast\Node) {
        echo "Check this {$file}\n" . ast_dump($left) . "\n" . ast_dump($parent) . "\n";
    }
    if ($left->kind == \ast\AST_STATIC_PROP && $left->children[0]->kind == \ast\AST_NAME) {
        if ($left->children[1] instanceof \ast\Node) {
            // This is some sort of self::${$key}  thing, give up
            return $right_type;
        }
        if ($left->children[0]->flags & \ast\flags\NAME_NOT_FQ) {
            $left_name = $namespace . $left->children[0]->children[0] . '::' . $left->children[1];
        } else {
            $left_name = $left->children[0]->children[0] . '::' . $left->children[1];
        }
    } else {
        $left_name = $left->children[0];
    }
    if ($right instanceof \ast\Node && $right->kind == \ast\AST_CLOSURE) {
        $right_type = 'callable:{closure ' . $right->id . '}';
        $vars[$left_name]['type'] = $right_type;
        $vars[$left_name]['tainted'] = false;
        $vars[$left_name]['tainted_by'] = '';
        return $right_type;
    }
    if (!$left_type && $right_type) {
        $left_type = $right_type;
    } else {
        if (!$left_type) {
            // We didn't figure out the type simply by looking at the left side of the assignment, check the right
            $right_type = node_type($file, $namespace, $right, $current_scope, $current_class, $taint);
            $left_type = $right_type;
        }
    }
    if ($parent->kind == \ast\AST_DIM && $left->kind == \ast\AST_VAR) {
        // Generics check - can't really do this without some special hint forcing a strict generics type
        /*
        if(!($left->children[0] instanceof \ast\Node)) {
        	if($right_type === "NULL") return ''; // You can assign null to any generic
        	$var_type = $scope[$current_scope]['vars'][$left->children[0]]['type'] ?? '';
        	if(!empty($var_type) && !nongenerics($var_type) && strpos($var_type, '[]') !== false) {
        		if(!type_check($right_type, generics($var_type))) {
        			Log::err(Log::ETYPE, "Assigning {$right_type} to \${$left->children[0]} which is {$var_type}", $file, $ast->lineno);
        			return '';
        		}
        	} else  {
        		$left_type = mkgenerics($right_type);
        	}
        }
        */
        $left_type = mkgenerics($right_type);
    }
    // $var->prop = ...
    if ($parent->kind == \ast\AST_PROP && $left->kind == \ast\AST_VAR) {
        // Check for $$var-> weirdness
        if (!$left->children[0] instanceof \ast\Node) {
            $prop = $parent->children[1];
            // Check for $var->$...
            if (!$prop instanceof \ast\Node) {
                $lclass = '';
                if ($left->children[0] == 'this') {
                    // $this->prop =
                    $class_name = $current_class['name'];
                } else {
                    $class_name = find_class_name($file, $parent, $namespace, $current_class, $current_scope);
                }
                $lclass = strtolower($class_name);
                if (empty($lclass) || empty($classes[$lclass])) {
                    return '';
                }
                $ltemp = find_property($file, $ast, $class_name, $prop, $current_class);
                if ($ltemp === false) {
                    return $right_type;
                }
                if (!empty($ltemp)) {
                    $lclass = $ltemp;
                }
                if (empty($classes[$lclass]['properties'][$prop])) {
                    $classes[$lclass]['properties'][$prop] = ['flags' => \ast\flags\MODIFIER_PUBLIC, 'name' => $prop, 'lineno' => 0, 'type' => $right_type];
                } else {
                    if (!empty($classes[$lclass]['properties'][$prop]['dtype'])) {
                        if ($ast->children[0]->kind == \ast\AST_DIM) {
                            $right_type = mkgenerics($right_type);
                        }
                        if (!type_check(all_types($right_type), all_types($classes[$lclass]['properties'][$prop]['dtype']))) {
                            Log::err(Log::ETYPE, "property is declared to be {$classes[$lclass]['properties'][$prop]['dtype']} but was assigned {$right_type}", $file, $ast->lineno);
                        }
                    }
                    $classes[$lclass]['properties'][$prop]['type'] = merge_type($classes[$lclass]['properties'][$prop]['type'], $right_type);
                }
                return $right_type;
            }
        }
    }
    if ($left_name instanceof \ast\Node) {
        // TODO: Deal with $$var
    } else {
        $vars[$left_name]['type'] = $left_type ?? '';
        $vars[$left_name]['tainted'] = $taint;
        $vars[$left_name]['tainted_by'] = $taint ? "{$file}:{$left->lineno}" : '';
    }
    return $right_type;
}
Exemplo n.º 3
0
 /**
  * Alias for find_property
  *
  * @author Anthony Short
  * @param $property
  * @param $css
  * @return array
  */
 public static function find_properties($property, $css = "")
 {
     if ($css == "") {
         $css =& self::$css;
     }
     return find_property($property, $css);
 }
Exemplo n.º 4
0
Arquivo: pass2.php Projeto: nikic/phan
function node_type($file, $namespace, $node, $current_scope, $current_class, &$taint = null, $check_var_exists = true)
{
    global $classes, $functions, $scope, $namespace_map, $internal_arginfo;
    if (!$node instanceof \ast\Node) {
        if ($node === null) {
            return '';
        }
        return type_map(gettype($node));
    } else {
        if ($node->kind == \ast\AST_ARRAY) {
            if (!empty($node->children) && $node->children[0] instanceof \ast\Node && $node->children[0]->kind == \ast\AST_ARRAY_ELEM) {
                // Check the first 5 (completely arbitrary) elements and assume the rest are the same type
                $etypes = [];
                for ($i = 0; $i < 5; $i++) {
                    if (empty($node->children[$i])) {
                        break;
                    }
                    if ($node->children[$i]->children[0] instanceof \ast\Node) {
                        $etypes[] = node_type($file, $namespace, $node->children[$i]->children[0], $current_scope, $current_class, $temp_taint);
                    } else {
                        $etypes[] = type_map(gettype($node->children[$i]->children[0]));
                    }
                }
                $types = array_unique($etypes);
                if (count($types) == 1 && !empty($types[0])) {
                    return mkgenerics($types[0]);
                }
            }
            return 'array';
        } else {
            if ($node->kind == \ast\AST_BINARY_OP || $node->kind == \ast\AST_GREATER || $node->kind == \ast\AST_GREATER_EQUAL) {
                if ($node->kind == \ast\AST_BINARY_OP) {
                    $node_flags = $node->flags;
                } else {
                    $node_flags = $node->kind;
                }
                $taint = var_taint_check($file, $node, $current_scope);
                switch ($node_flags) {
                    // Always a string from a concat
                    case \ast\flags\BINARY_CONCAT:
                        $temp_taint = false;
                        node_type($file, $namespace, $node->children[0], $current_scope, $current_class, $temp_taint);
                        if ($temp_taint) {
                            $taint = true;
                            return 'string';
                        }
                        node_type($file, $namespace, $node->children[1], $current_scope, $current_class, $temp_taint);
                        if ($temp_taint) {
                            $taint = true;
                        }
                        return 'string';
                        break;
                        // Boolean unless invalid operands
                    // Boolean unless invalid operands
                    case \ast\flags\BINARY_IS_IDENTICAL:
                    case \ast\flags\BINARY_IS_NOT_IDENTICAL:
                    case \ast\flags\BINARY_IS_EQUAL:
                    case \ast\flags\BINARY_IS_NOT_EQUAL:
                    case \ast\flags\BINARY_IS_SMALLER:
                    case \ast\flags\BINARY_IS_SMALLER_OR_EQUAL:
                    case \ast\AST_GREATER:
                    case \ast\AST_GREATER_EQUAL:
                        $temp = node_type($file, $namespace, $node->children[0], $current_scope, $current_class);
                        if (!$temp) {
                            $left = '';
                        } else {
                            $left = type_map($temp);
                        }
                        $temp = node_type($file, $namespace, $node->children[1], $current_scope, $current_class);
                        if (!$temp) {
                            $right = '';
                        } else {
                            $right = type_map($temp);
                        }
                        $taint = false;
                        // If we have generics and no non-generics on the left and the right is not array-like ...
                        if (!empty(generics($left)) && empty(nongenerics($left)) && !type_check($right, 'array')) {
                            Log::err(Log::ETYPE, "array to {$right} comparison", $file, $node->lineno);
                        } else {
                            // and the same for the right side
                            if (!empty(generics($right)) && empty(nongenerics($right)) && !type_check($left, 'array')) {
                                Log::err(Log::ETYPE, "{$left} to array comparison", $file, $node->lineno);
                            }
                        }
                        return 'bool';
                        break;
                        // Add is special because you can add arrays
                    // Add is special because you can add arrays
                    case \ast\flags\BINARY_ADD:
                        $temp = node_type($file, $namespace, $node->children[0], $current_scope, $current_class);
                        if (!$temp) {
                            $left = '';
                        } else {
                            $left = type_map($temp);
                        }
                        $temp = node_type($file, $namespace, $node->children[1], $current_scope, $current_class);
                        if (!$temp) {
                            $right = '';
                        } else {
                            $right = type_map($temp);
                        }
                        // fast-track common cases
                        if ($left == 'int' && $right == 'int') {
                            return 'int';
                        }
                        if (($left == 'int' || $left == 'float') && ($right == 'int' || $right == 'float')) {
                            return 'float';
                        }
                        $left_is_array = !empty(generics($left)) && empty(nongenerics($left));
                        $right_is_array = !empty(generics($right)) && empty(nongenerics($right));
                        if ($left_is_array && !type_check($right, 'array')) {
                            Log::err(Log::ETYPE, "invalid operator: left operand is array and right is not", $file, $node->lineno);
                            return '';
                        } else {
                            if ($right_is_array && !type_check($left, 'array')) {
                                Log::err(Log::ETYPE, "invalid operator: right operand is array and left is not", $file, $node->lineno);
                                return '';
                            } else {
                                if ($left_is_array || $right_is_array) {
                                    // If it is a '+' and we know one side is an array and the other is unknown, assume array
                                    return 'array';
                                }
                            }
                        }
                        return 'int|float';
                        $taint = false;
                        break;
                        // Everything else should be an int/float
                    // Everything else should be an int/float
                    default:
                        $temp = node_type($file, $namespace, $node->children[0], $current_scope, $current_class);
                        if (!$temp) {
                            $left = '';
                        } else {
                            $left = type_map($temp);
                        }
                        $temp = node_type($file, $namespace, $node->children[1], $current_scope, $current_class);
                        if (!$temp) {
                            $right = '';
                        } else {
                            $right = type_map($temp);
                        }
                        if ($left == 'array' || $right == 'array') {
                            Log::err(Log::ETYPE, "invalid array operator", $file, $node->lineno);
                            return '';
                        } else {
                            if ($left == 'int' && $right == 'int') {
                                return 'int';
                            } else {
                                if ($left == 'float' || $right == 'float') {
                                    return 'float';
                                }
                            }
                        }
                        return 'int|float';
                        $taint = false;
                        break;
                }
            } else {
                if ($node->kind == \ast\AST_CAST) {
                    $taint = var_taint_check($file, $node->children[0], $current_scope);
                    switch ($node->flags) {
                        case \ast\flags\TYPE_NULL:
                            return 'null';
                            break;
                        case \ast\flags\TYPE_BOOL:
                            $taint = false;
                            return 'bool';
                            break;
                        case \ast\flags\TYPE_LONG:
                            $taint = false;
                            return 'int';
                            break;
                        case \ast\flags\TYPE_DOUBLE:
                            $taint = false;
                            return 'float';
                            break;
                        case \ast\flags\TYPE_STRING:
                            return 'string';
                            break;
                        case \ast\flags\TYPE_ARRAY:
                            return 'array';
                            break;
                        case \ast\flags\TYPE_OBJECT:
                            return 'object';
                            break;
                        default:
                            Log::err(Log::EFATAL, "Unknown type (" . $node->flags . ") in cast");
                    }
                } else {
                    if ($node->kind == \ast\AST_NEW) {
                        $class_name = find_class_name($file, $node, $namespace, $current_class, $current_scope);
                        if ($class_name) {
                            return $classes[strtolower($class_name)]['type'];
                        }
                        return 'object';
                    } else {
                        if ($node->kind == \ast\AST_DIM) {
                            $taint = var_taint_check($file, $node->children[0], $current_scope);
                            $type = node_type($file, $namespace, $node->children[0], $current_scope, $current_class);
                            if (!empty($type)) {
                                $gen = generics($type);
                                if (empty($gen)) {
                                    if ($type !== 'null' && !type_check($type, 'string|ArrayAccess')) {
                                        // array offsets work on strings, unfortunately
                                        // Double check that any classes in the type don't have ArrayAccess
                                        $ok = false;
                                        foreach (explode('|', $type) as $t) {
                                            if (!empty($t) && !is_native_type($t)) {
                                                if (!empty($classes[strtolower($t)]['type'])) {
                                                    if (strpos('|' . $classes[strtolower($t)]['type'] . '|', '|ArrayAccess|') !== false) {
                                                        $ok = true;
                                                        break;
                                                    }
                                                }
                                            }
                                        }
                                        if (!$ok) {
                                            Log::err(Log::ETYPE, "Suspicious array access to {$type}", $file, $node->lineno);
                                        }
                                    }
                                    return '';
                                }
                            } else {
                                return '';
                            }
                            return $gen;
                        } else {
                            if ($node->kind == \ast\AST_VAR) {
                                return var_type($file, $node, $current_scope, $taint, $check_var_exists);
                            } else {
                                if ($node->kind == \ast\AST_ENCAPS_LIST) {
                                    foreach ($node->children as $encap) {
                                        if ($encap instanceof \ast\Node) {
                                            if (var_taint_check($file, $encap, $current_scope)) {
                                                $taint = true;
                                            }
                                        }
                                    }
                                    return "string";
                                } else {
                                    if ($node->kind == \ast\AST_CONST) {
                                        if ($node->children[0]->kind == \ast\AST_NAME) {
                                            if (defined($node->children[0]->children[0])) {
                                                return type_map(gettype(constant($node->children[0]->children[0])));
                                            } else {
                                                // Todo: user-defined constant
                                            }
                                        }
                                    } else {
                                        if ($node->kind == \ast\AST_CLASS_CONST) {
                                            if ($node->children[1] == 'class') {
                                                return 'string';
                                            }
                                            // class name fetch
                                            $class_name = find_class_name($file, $node, $namespace, $current_class, $current_scope);
                                            if (!$class_name) {
                                                return '';
                                            }
                                            $ltemp = strtolower($class_name);
                                            while ($ltemp && !array_key_exists($node->children[1], $classes[$ltemp]['constants'])) {
                                                $ltemp = strtolower($classes[$ltemp]['parent']);
                                                if (empty($classes[$ltemp])) {
                                                    return '';
                                                }
                                                // undeclared class - will be caught elsewhere
                                            }
                                            if (!$ltemp || !array_key_exists($node->children[1], $classes[$ltemp]['constants'])) {
                                                Log::err(Log::EUNDEF, "can't access undeclared constant {$class_name}::{$node->children[1]}", $file, $node->lineno);
                                                return '';
                                            }
                                            return $classes[$ltemp]['constants'][$node->children[1]]['type'];
                                        } else {
                                            if ($node->kind == \ast\AST_PROP) {
                                                if ($node->children[0]->kind == \ast\AST_VAR) {
                                                    $class_name = find_class_name($file, $node, $namespace, $current_class, $current_scope);
                                                    if ($class_name && !$node->children[1] instanceof \ast\Node) {
                                                        $ltemp = find_property($file, $node, $class_name, $node->children[1], $class_name, false);
                                                        if (empty($ltemp)) {
                                                            return '';
                                                        }
                                                        return $classes[$ltemp]['properties'][$node->children[1]]['type'];
                                                    }
                                                }
                                            } else {
                                                if ($node->kind == \ast\AST_STATIC_PROP) {
                                                    if ($node->children[0]->kind == \ast\AST_NAME) {
                                                        $class_name = qualified_name($file, $node->children[0], $namespace);
                                                        if ($class_name && !$node->children[1] instanceof \ast\Node) {
                                                            $ltemp = find_property($file, $node, $class_name, $node->children[1], $class_name, false);
                                                            if (empty($ltemp)) {
                                                                return '';
                                                            }
                                                            return $classes[$ltemp]['properties'][$node->children[1]]['type'];
                                                        }
                                                    }
                                                } else {
                                                    if ($node->kind == \ast\AST_CALL) {
                                                        if ($node->children[0]->kind == \ast\AST_NAME) {
                                                            $func_name = $node->children[0]->children[0];
                                                            if ($node->children[0]->flags & \ast\flags\NAME_NOT_FQ) {
                                                                $func = $namespace_map[T_FUNCTION][$file][strtolower($namespace . $func_name)] ?? $namespace_map[T_FUNCTION][$file][strtolower($func_name)] ?? $functions[strtolower($namespace . $func_name)] ?? $functions[strtolower($func_name)] ?? null;
                                                            } else {
                                                                $func = $functions[strtolower($func_name)] ?? null;
                                                            }
                                                            if ($func['file'] == 'internal' && empty($func['ret'])) {
                                                                if (!empty($internal_arginfo[$func_name])) {
                                                                    return $internal_arginfo[$func_name][0] ?? '';
                                                                }
                                                            } else {
                                                                return $func['ret'] ?? '';
                                                            }
                                                        } else {
                                                            // TODO: Handle $func() and other cases that get here
                                                        }
                                                    } else {
                                                        if ($node->kind == \ast\AST_STATIC_CALL) {
                                                            $class_name = find_class_name($file, $node, $namespace, $current_class, $current_scope);
                                                            $method = find_method($class_name, $node->children[1]);
                                                            if ($method) {
                                                                return $method['ret'] ?? '';
                                                            }
                                                        } else {
                                                            if ($node->kind == \ast\AST_METHOD_CALL) {
                                                                $class_name = find_class_name($file, $node, $namespace, $current_class, $current_scope);
                                                                if ($class_name) {
                                                                    $method_name = $node->children[1];
                                                                    $method = find_method($class_name, $method_name);
                                                                    if ($method === false) {
                                                                        Log::err(Log::EUNDEF, "call to undeclared method {$class_name}->{$method_name}()", $file, $node->lineno);
                                                                    } else {
                                                                        if ($method != 'dynamic') {
                                                                            return $method['ret'];
                                                                        }
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    return '';
}