import os import re # Directories to scan DIRS = ['./app', './Modules', './database'] # Patterns to search for # 1. MySQL specific functions PATTERNS = { 'MONTHNAME': r'MONTHNAME\(', 'DATE_FUNCTION': r'DATE\((?!\s*[\'"])', # Avoid matching strings like DATE('2023-01-01') 'YEAR_FUNCTION': r'YEAR\(', 'MONTH_FUNCTION': r'MONTH\(', 'DAY_FUNCTION': r'DAY\(', 'IFNULL': r'IFNULL\(', } # 2. Unquoted camelCase identifiers in raw SQL # This is tricky, but we can look for selectRaw, DB::raw, sum(DB::raw), etc. RAW_SQL_PATTERN = r'(?:selectRaw|DB::raw|sum\(DB::raw)\(([\'"])(.*?)\1\)' def is_mixed_case(s): return any(c.islower() for c in s) and any(c.isupper() for c in s) def audit(): results = [] for root_dir in DIRS: for root, dirs, files in os.walk(root_dir): for file in files: if file.endswith('.php'): path = os.path.join(root, file) with open(path, 'r', encoding='utf-8', errors='ignore') as f: lines = f.readlines() for i, line in enumerate(lines): # Check for function patterns for name, pattern in PATTERNS.items(): if re.search(pattern, line): results.append(f"{path}:{i+1} - Found {name}: {line.strip()}") # Check for unquoted mixed case in raw SQL matches = re.finditer(RAW_SQL_PATTERN, line) for match in matches: sql = match.group(2) # Simple check for mixed case words not in quotes words = re.findall(r'\b\w+\b', sql) for word in words: if is_mixed_case(word): # Check if it's already double-quoted if f'"{word}"' not in sql: results.append(f"{path}:{i+1} - Unquoted mixed-case '{word}' in SQL: {line.strip()}") return results if __name__ == "__main__": findings = audit() if findings: print("\n".join(findings)) else: print("No PostgreSQL incompatibilities found.")