public static PhpToken[] GetBlock(PhpToken[] tokens, int index)
        {
            var start = index;

            if (tokens[index].TokenType != PhpTokenType.LeftBrace)
            {
                throw new InvalidOperationException("Block must begin with a left brace.");
            }

            int depth = 1;

            while (depth != 0)
            {
                var t = tokens[++index];

                if (t.TokenType == PhpTokenType.LeftBrace)
                {
                    depth++;
                }
                else if (t.TokenType == PhpTokenType.RightBrace)
                {
                    depth--;
                }
            }

            var tokenCount = index - start + 1;
            var blockTokens = new PhpToken[tokenCount];
            Array.Copy(tokens, start, blockTokens, 0, tokenCount);

            return blockTokens;
        }
        public string AnnotateBlock(string file, string code, PhpToken[] tokens,
            int tokenIndex, bool functionsOnly)
        {
            if (tokens[tokenIndex - 1].TokenType != PhpTokenType.RightParenthesis &&
                !tokens[tokenIndex - 1].IsKeyword())
            {
                return code;
            }

            for (int i = tokenIndex; i >= 0; i--)
            {
                if (tokens[i].IsKeyword())
                {
                    if (tokens[i].Lexeme == "switch" ||
                        (functionsOnly && tokens[i].Lexeme != "function"))
                        return code;

                    break;
                }
            }

            code = Annotate(file, code, tokens[tokenIndex].Index + 1);

            return code;
        }
        public static PhpToken[] GetGlobalFunctionCallIds(PhpToken[] tokens)
        {
            var functionCalls = new List<PhpToken>();

            int state = 0;

            for (int i = 0; i < tokens.Length; i++)
            {
                if (state == 0 &&
                    (tokens[i].TokenType == PhpTokenType.ObjectOperator ||
                    tokens[i].TokenType == PhpTokenType.ScopeResolutionOperator))
                    state = -1;
                else if ((state == 0 || state == 1) && tokens[i].TokenType == PhpTokenType.Identifier)
                    state = 1;
                else if (state == 1 && tokens[i].TokenType == PhpTokenType.LeftParenthesis)
                {
                    functionCalls.Add(tokens[i - 1]);

                    state = 0;
                }
                else if (tokens[i].TokenType != PhpTokenType.WhiteSpace &&
                    tokens[i].TokenType != PhpTokenType.Comment)
                    state = 0;
            }

            return functionCalls.ToArray();
        }
        protected string GetSurroundingCode(string code, PhpToken token)
        {
            var line = code.GetLineNumber(token.Index);
            var code2 = code.InsertLineNumbers();
            var index = code2.GetLineIndex(line);

            return code2.GetSurroundingLines(index, 9, 9);
        }
 public override StaticAnalysisAlert[] GetAlerts(string code, PhpToken[] tokens)
 {
     return tokens
         .Where(x =>
             x.TokenType == PhpTokenType.BacktickString &&
             Php.Superglobals
                 .Any(y => x.Lexeme.Contains(y)))
         .Select(x => CreateAlert(code, x))
         .ToArray();
 }
        public ExpressionWalker(PhpToken[] tokens, params ExpressionAnalyzer[] analyzers)
        {
            Analyzers = new List<ExpressionAnalyzer>();

            if (analyzers != null)
            {
                Analyzers.AddRange(analyzers);
            }

            _tokens = tokens;
        }
 public static void IsValid(TokenPairs pairs)
 {
     var text = string.Join("", pairs.Select(pair => pair.Value).ToArray());
     var lexer = new PhpLexer(text);
     int index = 0;
     var expected = pairs.Select(pair =>
     {
         var token = new PhpToken(pair.Key, pair.Value, index);
         index += pair.Value.Length;
         return token;
     });
     List<PhpToken> actual = lexer.GetTokens();
     CollectionAssert.AreEqual(expected, actual);
 }
        public static Dictionary<string, List<string>> FindSuperglobalFields(PhpToken[] tokens)
        {
            var fields = PhpParser.GetSuperglobalFields(tokens);

            foreach (var superglobal in tokens
                .Where(x => x.TokenType == PhpTokenType.String ||
                    x.TokenType == PhpTokenType.HereDocString ||
                    x.TokenType == PhpTokenType.BacktickString)
                .Select(x => GetSuperGlobalFieldsFromText(x.Lexeme))
                .SelectMany(x => x))
                fields[superglobal.Key].AddRange(superglobal.Value);

            return fields;
        }
        public void AddValues(string filename, PhpToken[] tokens)
        {
            var walker = new ExpressionWalker(
                tokens,
                new BooleanExpressionAnalyzer(),
                new SwitchStatementAnalyzer());

            var valueTable = new SuperGlobalValueTable(filename);

            walker.Walk();
            walker.Analyzers.Iter(x =>
            {
                x.Matches.Iter(y =>
                {
                    var id = y.Tokens[0].Lexeme;
                    var list = valueTable[id];

                    if (list == null)
                    {
                        list = new SuperGlobalValueList(id);
                        valueTable.Add(list);
                    }

                    Func<string, string> s = a => a.Substring(1, a.Length - 2);

                    if (x is BooleanExpressionAnalyzer)
                    {
                        list.Values.Add(
                            new SuperGlobalNameValuePair(
                                s(y.Tokens[1].Lexeme),
                                s(y.Tokens[3].Lexeme)));
                    }
                    else if (x is SwitchStatementAnalyzer)
                    {
                        list.Values.AddRange(
                            y.Tokens
                                .Skip(2)
                                .Select(z => new SuperGlobalNameValuePair(
                                    s(y.Tokens[1].Lexeme),
                                    s(z.Lexeme))));
                    }
                });
            });

            lock (PageTable)
            {
                PageTable.Add(valueTable);
            }
        }
 protected override void AnalyzeCore(PhpToken token)
 {
     if (token.TokenType == PhpTokenType.WhiteSpace ||
         token.TokenType == PhpTokenType.Comment)
     {
         return;
     }
     else if (State == 0 &&
         token.TokenType == PhpTokenType.Variable &&
         PhpName.Superglobals.Contains(token.Lexeme))
     {
         AddExpressionToken();
     }
     else if (State == 1 && token.TokenType == PhpTokenType.LeftBracket)
     {
         State++;
     }
     else if (State == 2 && token.TokenType == PhpTokenType.String)
     {
         AddExpressionToken();
     }
     else if (State == 3 && token.TokenType == PhpTokenType.RightBracket)
     {
         State++;
     }
     else if (State == 4 && _operators.Contains(token.TokenType))
     {
         AddExpressionToken();
     }
     else if (State == 5 && token.TokenType == PhpTokenType.String)
     {
         AddExpressionToken();
         AddExpression();
     }
     else
     {
         NewExpression();
     }
 }
        public static PhpToken[] GetArrayAccesses(PhpToken[] tokens)
        {
            var functionCalls = new List<PhpToken>();

            int state = 0;

            for (int i = 0; i < tokens.Length; i++)
            {
                if ((state == 0 || state == 1) && tokens[i].TokenType == PhpTokenType.Variable)
                    state = 1;
                else if (state == 1 && tokens[i].TokenType == PhpTokenType.LeftBracket)
                {
                    functionCalls.Add(tokens[i - 1]);

                    state = 0;
                }
                else if (tokens[i].TokenType != PhpTokenType.WhiteSpace &&
                    tokens[i].TokenType != PhpTokenType.Comment)
                    state = 0;
            }

            return functionCalls.ToArray();
        }
        public override StaticAnalysisAlert[] GetAlerts(string code, PhpToken[] tokens)
        {
            var functions = PhpParser.GetGlobalFunctionCalls(tokens);

            var sanitizationFunctions = GetSanitizationFunctions();
            var targetFunctionNames = GetFunctions();
            var targetFunctionCalls = functions
                .Where(x => targetFunctionNames.Contains(x.Id.Lexeme) &&
                    !x.ParamTokens.Any(y => sanitizationFunctions.Contains(y.Lexeme)));
            var insecureCalls = targetFunctionCalls.Where(IsCallInsecure);

            return insecureCalls
                .Select(x =>
                {
                    var line = code.GetLineNumber(x.Id.Index);
                    var code2 = code.InsertLineNumbers();
                    var index = code2.GetLineIndex(line);

                    return new StaticAnalysisAlert(Name, line + 1,
                        code2.GetSurroundingLines(index, 9, 9));
                })
                .ToArray();
        }
        public static Dictionary<string, List<string>> GetSuperglobalFields(PhpToken[] tokens)
        {
            var fieldDictionary = Php.Superglobals
                .ToDictionary(x => x, x => new List<string>());

            for (int i = 0; i < tokens.Length; i++)
                if (Php.Superglobals.Contains(tokens[i].Lexeme))
                {
                    int state = 0;
                    string fieldName = null;

                    for (int j = i + 1; j < tokens.Length; j++)
                    {
                        if (state == 0 && tokens[j].TokenType == PhpTokenType.LeftBracket)
                        {
                            state = 1;
                        }
                        else if (state == 1 && tokens[j].TokenType == PhpTokenType.String)
                        {
                            state = 2;
                            fieldName = tokens[j].Lexeme;
                        }
                        else if (state == 2 && tokens[j].TokenType == PhpTokenType.RightBracket)
                        {
                            state = 3;
                            break;
                        }
                        else
                            break;
                    }

                    if (state == 3)
                    {
                        var name = fieldName.Substring(1, fieldName.Length - 2);

                        if (!fieldDictionary[tokens[i].Lexeme].Contains(name))
                            fieldDictionary[tokens[i].Lexeme].Add(name);
                    }
                }

            return fieldDictionary;
        }
        public static string[] GetIncludedFiles(PhpToken[] tokens)
        {
            var includedFiles = new List<string>();

            for (int i = 0; i < tokens.Length; i++)
                if (Php.IncludeFunctions.Contains(tokens[i].Lexeme))
                {
                    int state = 0;
                    string filename = null;

                    for (int j = i + 1; j < tokens.Length; j++)
                    {
                        if (state == 0 && tokens[j].TokenType == PhpTokenType.LeftParenthesis)
                        {
                            state = 1;
                        }
                        else if (state == 0 && tokens[j].TokenType == PhpTokenType.String)
                        {
                            state = 4;
                            filename = tokens[j].Lexeme;
                        }
                        else if (state == 1 && tokens[j].TokenType == PhpTokenType.String)
                        {
                            state = 2;
                            filename = tokens[j].Lexeme;
                        }
                        else if (state == 2 && tokens[j].TokenType == PhpTokenType.RightParenthesis)
                        {
                            state = 3;
                            break;
                        }
                        else if (state == 4 && tokens[j].TokenType == PhpTokenType.EndOfStatement)
                        {
                            state = 3;
                            break;
                        }
                        else
                            break;
                    }

                    if (state == 3)
                    {
                        includedFiles.Add(filename.Substring(1, filename.Length - 2));
                    }
                }

            return includedFiles.ToArray();
        }
        public void Set(ref string PHP)
        {
            var lexer = new PhpLexer(PHP);
            var tokens = lexer.GetTokens().ToArray();
            var unk = tokens.Where(x => x.TokenType == PhpTokenType.Unknown);

            #if DEBUG
            if (unk.Any())
                throw new InvalidOperationException();
            #endif

            var funcTokens = StartDelimiter == '(' ?
                PhpParser.GetGlobalFunctionCallIds(tokens) :
                PhpParser.GetArrayAccesses(tokens);

            for (int i = funcTokens.Length - 1; i >= 0; i--)
            {
                if (funcTokens[i].Lexeme != FunctionName)
                    continue;

                if (StartDelimiter == '(')
                {
                    PHP = PHP.Remove(funcTokens[i].Index, funcTokens[i].Lexeme.Length);
                    PHP = PHP.Insert(funcTokens[i].Index, ReplacementName);
                }
                else
                {
                    var tokenIndex = Array.IndexOf(tokens, tokens.Single(x => x.Index == funcTokens[i].Index));
                    PhpToken leftBracket = new PhpToken(), rightBracket = new PhpToken();
                    for (int j = tokenIndex + 1; j < tokens.Length; j++)
                    {
                        if (tokens[j].TokenType == PhpTokenType.LeftBracket)
                            leftBracket = tokens[j];
                        else if (tokens[j].TokenType == PhpTokenType.RightBracket)
                        {
                            rightBracket = tokens[j];
                            break;
                        }
                    }
                    if (leftBracket.TokenType != PhpTokenType.LeftBracket)
                        continue;

                    PHP = PHP.Insert(rightBracket.Index, ")");
                    PHP = PHP.Insert(leftBracket.Index + 1, ReplacementName + "(");
                }
            }
        }
 protected StaticAnalysisAlert CreateAlert(string code, PhpToken token)
 {
     return new StaticAnalysisAlert(Name,
         code.GetLineNumber(token.Index) + 1,
         GetSurroundingCode(code, token));
 }
 public abstract StaticAnalysisAlert[] GetAlerts(string code, PhpToken[] tokens);
        protected override void AnalyzeCore(PhpToken token)
        {
            if (token.TokenType == PhpTokenType.WhiteSpace ||
                token.TokenType == PhpTokenType.Comment)
            {
                return;
            }
            else if (State == 0 && token.TokenType == PhpTokenType.switchKeyword)
            {
                State++;
            }
            else if (State == 1 && token.TokenType == PhpTokenType.LeftParenthesis)
            {
                State++;
            }
            else if (State == 2 &&
                token.TokenType == PhpTokenType.Variable &&
                Php.Superglobals.Contains(token.Lexeme))
            {
                AddExpressionToken();
            }
            else if (State == 3 && token.TokenType == PhpTokenType.LeftBracket)
            {
                State++;
            }
            else if (State == 4 && token.TokenType == PhpTokenType.String)
            {
                AddExpressionToken();
            }
            else if (State == 5 && token.TokenType == PhpTokenType.RightBracket)
            {
                State++;
            }
            else if (State == 6 && token.TokenType == PhpTokenType.RightParenthesis)
            {
                State++;
            }
            else if (State == 7)
            {
                if (token.TokenType == PhpTokenType.RightBrace)
                {
                    AddExpression();
                }
                else if (token.TokenType == PhpTokenType.caseKeyword)
                {
                    State++;
                }
            }
            else if (State == 8)
            {
                if (token.TokenType == PhpTokenType.String)
                {
                    AddExpressionToken();
                }

                State = 7;
            }
            else
            {
                NewExpression();
            }
        }
 public static PhpToken[] StripWhitespaceAndComments(PhpToken[] tokens)
 {
     return tokens
         .Where(x =>
             x.TokenType != PhpTokenType.WhiteSpace &&
             x.TokenType != PhpTokenType.Comment)
         .ToArray();
 }
 protected abstract void AnalyzeCore(PhpToken token);
 public void Analyze(PhpToken token)
 {
     _currentToken = token;
     AnalyzeCore(token);
 }
 public IEnumerable<StaticAnalysisAlert> GetAlerts(string code, PhpToken[] tokens)
 {
     return _plugins.SelectMany(x => x.GetAlerts(code, tokens));
 }
        public string AnnotateCode(string file, string php, PhpToken[] tokens)
        {
            lock (AnnotationIndexes)
            {
                AnnotationIndexes.Add(file, 0);
                AnnotationTable.Add(file);
            }

            for (int i = tokens.Length - 1; i >= 0; i--)
            {
                if (tokens[i].TokenType == PhpTokenType.LeftBrace)
                {
                    php = AnnotateBlock(file, php,
                        tokens, i, Config.CodeCoverageReport == 1);
                }
            }

            var open = tokens.FirstOrDefault(x => x.TokenType == PhpTokenType.OpenTag);

            if (open.Lexeme != null)
            {
                php = Annotate(file, php, open.Index + open.Lexeme.Length);
            }
            else
            {
                var tmp = Annotate(file, "<?php  ?>", 6);
                php = tmp + php;
            }

            return php;
        }
 public FunctionCall(PhpToken id, PhpToken[] parameters)
 {
     Id = id;
     ParamTokens = parameters;
 }
        public static List<FunctionCall> GetGlobalFunctionCalls(PhpToken[] tokens)
        {
            int state = 0;

            var calls = new List<FunctionCall>();

            FunctionCall call = new FunctionCall();
            List<PhpToken> paramTokens = null;

            for (int i = 0; i < tokens.Length; i++)
            {
                if (state == 0 &&
                    (tokens[i].TokenType == PhpTokenType.ObjectOperator ||
                    tokens[i].TokenType == PhpTokenType.ScopeResolutionOperator))
                    state = -1;
                else if ((state == 0 || state == 1) &&
                    (tokens[i].TokenType == PhpTokenType.Identifier || tokens[i].TokenType == PhpTokenType.Variable))
                {
                    state = 1;

                    call = new FunctionCall();
                    call.Id = tokens[i];
                    paramTokens = new List<PhpToken>();
                }
                else if (state == 1 && tokens[i].TokenType == PhpTokenType.LeftParenthesis)
                {
                    paramTokens.Add(tokens[i]);
                    state = 2;
                }
                else if (state > 1)
                {
                    paramTokens.Add(tokens[i]);

                    if (tokens[i].TokenType == PhpTokenType.LeftParenthesis)
                        state++;
                    else if (tokens[i].TokenType == PhpTokenType.RightParenthesis)
                        state--;

                    if (state <= 1)
                    {
                        call.ParamTokens = paramTokens.ToArray();
                        calls.Add(call);
                        state = 0;
                    }

                }
                else if (tokens[i].TokenType != PhpTokenType.WhiteSpace &&
                    tokens[i].TokenType != PhpTokenType.Comment)
                    state = 0;
            }

            return calls;
        }
 public void Token_ToString()
 {
     var token = new PhpToken(PhpTokenType.OpenTag, "<?", 0);
     Assert.AreEqual("[0] OpenTag: <?", token.ToString());
 }