1+ name : PHP Static Code Analysis
2+
3+ on :
4+ push :
5+ branches : [ main, master, develop ]
6+ pull_request :
7+ branches : [ main, master, develop ]
8+
9+ jobs :
10+ static-analysis :
11+ runs-on : ubuntu-latest
12+
13+ strategy :
14+ matrix :
15+ php-version : ['7.4', '8.0', '8.1', '8.2']
16+
17+ steps :
18+ - name : Checkout code
19+ uses : actions/checkout@v4
20+
21+ - name : Setup PHP
22+ uses : shivammathur/setup-php@v2
23+ with :
24+ php-version : ${{ matrix.php-version }}
25+ extensions : curl, json, mbstring, openssl
26+ coverage : none
27+
28+ - name : Install PHPStan
29+ run : |
30+ wget https://github.com/phpstan/phpstan/releases/latest/download/phpstan.phar
31+ chmod +x phpstan.phar
32+ sudo mv phpstan.phar /usr/local/bin/phpstan
33+
34+ - name : Install PHP_CodeSniffer
35+ run : |
36+ composer global require squizlabs/php_codesniffer
37+ echo "$HOME/.composer/vendor/bin" >> $GITHUB_PATH
38+
39+ - name : Create PHPStan configuration
40+ run : |
41+ cat > phpstan.neon << 'EOF'
42+ parameters:
43+ level: 3
44+ paths:
45+ - src/
46+ - examples/
47+ excludePaths:
48+ - src/vendor/
49+ checkMissingIterableValueType: false
50+ checkGenericClassInNonGenericObjectType: false
51+ ignoreErrors:
52+ - '#Call to an undefined method [a-zA-Z0-9\\_]+::[a-zA-Z0-9\\_]+\(\)#'
53+ - '#Access to an undefined property [a-zA-Z0-9\\_]+::\$[a-zA-Z0-9\\_]+#'
54+ - '#Undefined variable \$[a-zA-Z0-9\\_]+#'
55+ - '#Undefined constant [a-zA-Z0-9\\_]+#'
56+ EOF
57+
58+ - name : Run PHPStan
59+ run : phpstan analyse --no-progress
60+
61+ - name : Create PHP_CodeSniffer configuration
62+ run : |
63+ cat > phpcs.xml << 'EOF'
64+ <?xml version="1.0"?>
65+ <ruleset name="Cloudpods PHP SDK">
66+ <description>PHP_CodeSniffer rules for Cloudpods PHP SDK</description>
67+
68+ <!-- Include all files in src and examples directories -->
69+ <file>src/</file>
70+ <file>examples/</file>
71+
72+ <!-- Exclude vendor directory -->
73+ <exclude-pattern>*/vendor/*</exclude-pattern>
74+
75+ <!-- Use PSR-12 standard -->
76+ <rule ref="PSR12"/>
77+
78+ <!-- Custom rules -->
79+ <rule ref="Generic.Files.LineLength">
80+ <properties>
81+ <property name="lineLimit" value="120"/>
82+ <property name="absoluteLineLimit" value="150"/>
83+ </properties>
84+ </rule>
85+
86+ <!-- Ignore some common issues for this project -->
87+ <rule ref="PSR1.Classes.ClassDeclaration.MissingNamespace">
88+ <exclude-pattern>*/examples/*</exclude-pattern>
89+ </rule>
90+
91+ <rule ref="PSR1.Files.SideEffects.FoundWithSymbols">
92+ <exclude-pattern>*/examples/*</exclude-pattern>
93+ </rule>
94+
95+ <!-- Allow short array syntax for this project -->
96+ <rule ref="Generic.Arrays.DisallowShortArraySyntax">
97+ <exclude-pattern>*</exclude-pattern>
98+ </rule>
99+ </ruleset>
100+ EOF
101+
102+ - name : Run PHP_CodeSniffer
103+ run : phpcs --standard=phpcs.xml --colors
104+
105+ - name : Check for syntax errors
106+ run : |
107+ echo "Checking PHP syntax..."
108+ find src/ examples/ -name "*.php" -exec php -l {} \;
109+
110+ - name : Run basic linting
111+ run : |
112+ echo "Running basic linting checks..."
113+ find src/ examples/ -name "*.php" -exec php -r "
114+ \$file = \$argv[1];
115+ \$content = file_get_contents(\$file);
116+
117+ // Check for common issues
118+ \$issues = [];
119+
120+ // Check for unclosed quotes
121+ if (substr_count(\$content, '\"') % 2 !== 0) {
122+ \$issues[] = 'Unclosed double quotes';
123+ }
124+ if (substr_count(\$content, \"'\") % 2 !== 0) {
125+ \$issues[] = 'Unclosed single quotes';
126+ }
127+
128+ // Check for unclosed brackets
129+ if (substr_count(\$content, '{') !== substr_count(\$content, '}')) {
130+ \$issues[] = 'Unclosed braces';
131+ }
132+ if (substr_count(\$content, '(') !== substr_count(\$content, ')')) {
133+ \$issues[] = 'Unclosed parentheses';
134+ }
135+
136+ // Check for missing semicolons (basic check)
137+ \$lines = explode(\"\\n\", \$content);
138+ foreach (\$lines as \$lineNum => \$line) {
139+ \$line = trim(\$line);
140+ if (!empty(\$line) && !preg_match('/^[\/\*#\s\{\}\(\)\[\]]/', \$line)) {
141+ if (!preg_match('/[;\{\}]$/', \$line)) {
142+ \$issues[] = 'Possible missing semicolon on line ' . (\$lineNum + 1);
143+ }
144+ }
145+ }
146+
147+ if (!empty(\$issues)) {
148+ echo \"Issues found in \$file:\\n\";
149+ foreach (\$issues as \$issue) {
150+ echo \" - \$issue\\n\";
151+ }
152+ exit(1);
153+ }
154+ " {} \;
155+
156+ - name : Check file structure
157+ run : |
158+ echo "Checking file structure..."
159+ echo "PHP files found:"
160+ find src/ examples/ -name "*.php" | wc -l
161+ echo "Directories:"
162+ find src/ examples/ -type d | sort
163+
164+ - name : Check for common PHP issues
165+ run : |
166+ echo "Checking for common PHP issues..."
167+ find src/ examples/ -name "*.php" -exec php -r "
168+ \$file = \$argv[1];
169+ \$content = file_get_contents(\$file);
170+
171+ // Check for potential issues
172+ \$warnings = [];
173+
174+ // Check for hardcoded paths
175+ if (preg_match('/\/home\/|\/var\/|\/tmp\//', \$content)) {
176+ \$warnings[] = 'Hardcoded paths detected';
177+ }
178+
179+ // Check for debug code
180+ if (preg_match('/var_dump\(|print_r\(|die\(|exit\(/', \$content)) {
181+ \$warnings[] = 'Debug code detected (var_dump, print_r, die, exit)';
182+ }
183+
184+ // Check for potential security issues
185+ if (preg_match('/eval\(|exec\(|system\(|shell_exec\(/', \$content)) {
186+ \$warnings[] = 'Potentially dangerous functions detected';
187+ }
188+
189+ if (!empty(\$warnings)) {
190+ echo \"Warnings in \$file:\\n\";
191+ foreach (\$warnings as \$warning) {
192+ echo \" - \$warning\\n\";
193+ }
194+ }
195+ " {} \;
196+
197+ - name : Generate analysis report
198+ if : always()
199+ run : |
200+ echo "## PHP Static Analysis Report" >> $GITHUB_STEP_SUMMARY
201+ echo "" >> $GITHUB_STEP_SUMMARY
202+ echo "**PHP Version:** ${{ matrix.php-version }}" >> $GITHUB_STEP_SUMMARY
203+ echo "**Analysis Date:** $(date)" >> $GITHUB_STEP_SUMMARY
204+ echo "" >> $GITHUB_STEP_SUMMARY
205+ echo "### Analysis Tools Used:" >> $GITHUB_STEP_SUMMARY
206+ echo "- PHPStan (Level 3)" >> $GITHUB_STEP_SUMMARY
207+ echo "- PHP_CodeSniffer (PSR-12)" >> $GITHUB_STEP_SUMMARY
208+ echo "- PHP Syntax Check" >> $GITHUB_STEP_SUMMARY
209+ echo "- Basic Linting" >> $GITHUB_STEP_SUMMARY
210+ echo "- Security Checks" >> $GITHUB_STEP_SUMMARY
211+ echo "" >> $GITHUB_STEP_SUMMARY
212+ echo "### Directories Analyzed:" >> $GITHUB_STEP_SUMMARY
213+ echo "- src/" >> $GITHUB_STEP_SUMMARY
214+ echo "- examples/" >> $GITHUB_STEP_SUMMARY
215+ echo "" >> $GITHUB_STEP_SUMMARY
216+ echo "### Files Checked:" >> $GITHUB_STEP_SUMMARY
217+ find src/ examples/ -name "*.php" | wc -l | xargs echo "- Total PHP files:" >> $GITHUB_STEP_SUMMARY
0 commit comments