Failed Conditions
Push — feature/scrutinizer-send-pass-... ( 5c2dd9 )
by Juliette
02:12
created

RemovedExtensionsSniff::getErrorMsgTemplate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
eloc 1
nc 1
nop 0
1
<?php
2
/**
3
 * \PHPCompatibility\Sniffs\PHP\RemovedExtensionsSniff.
4
 *
5
 * @category  PHP
6
 * @package   PHPCompatibility
7
 * @author    Wim Godden <[email protected]>
8
 * @copyright 2012 Cu.be Solutions bvba
9
 */
10
11
namespace PHPCompatibility\Sniffs\PHP;
12
13
use PHPCompatibility\AbstractRemovedFeatureSniff;
14
15
/**
16
 * \PHPCompatibility\Sniffs\PHP\RemovedExtensionsSniff.
17
 *
18
 * Discourages the use of removed extensions. Suggests alternative extensions if available
19
 *
20
 * @category  PHP
21
 * @package   PHPCompatibility
22
 * @author    Wim Godden <[email protected]>
23
 * @copyright 2012 Cu.be Solutions bvba
24
 */
25
class RemovedExtensionsSniff extends AbstractRemovedFeatureSniff
26
{
27
    /**
28
     * A list of functions to whitelist, if any.
29
     *
30
     * This is intended for projects using functions which start with the same
31
     * prefix as one of the removed extensions.
32
     *
33
     * This property can be set from the ruleset, like so:
34
     * <rule ref="PHPCompatibility.PHP.RemovedExtensions">
35
     *   <properties>
36
     *     <property name="functionWhitelist" type="array" value="mysql_to_rfc3339,mysql_another_function" />
37
     *   </properties>
38
     * </rule>
39
     *
40
     * @var array
41
     */
42
    public $functionWhitelist;
43
44
    /**
45
     * A list of removed extensions with their alternative, if any
46
     *
47
     * The array lists : version number with false (deprecated) and true (removed).
48
     * If's sufficient to list the first version where the extension was deprecated/removed.
49
     *
50
     * @var array(string|null)
51
     */
52
    protected $removedExtensions = array(
53
        'activescript' => array(
54
            '5.1' => true,
55
            'alternative' => 'pecl/activescript',
56
        ),
57
        'cpdf' => array(
58
            '5.1' => true,
59
            'alternative' => 'pecl/pdflib',
60
        ),
61
        'dbase' => array(
62
            '5.3' => true,
63
            'alternative' => null,
64
        ),
65
        'dbx' => array(
66
            '5.1' => true,
67
            'alternative' => 'pecl/dbx',
68
        ),
69
        'dio' => array(
70
            '5.1' => true,
71
            'alternative' => 'pecl/dio',
72
        ),
73
        'ereg' => array(
74
            '5.3' => false,
75
            '7.0' => true,
76
            'alternative' => 'pcre',
77
        ),
78
        'fam' => array(
79
            '5.1' => true,
80
            'alternative' => null,
81
        ),
82
        'fbsql' => array(
83
            '5.3' => true,
84
            'alternative' => null,
85
        ),
86
        'fdf' => array(
87
            '5.3' => true,
88
            'alternative' => 'pecl/fdf',
89
        ),
90
        'filepro' => array(
91
            '5.2' => true,
92
            'alternative' => null,
93
        ),
94
        'hw_api' => array(
95
            '5.2' => true,
96
            'alternative' => null,
97
        ),
98
        'ingres' => array(
99
            '5.1' => true,
100
            'alternative' => 'pecl/ingres',
101
        ),
102
        'ircg' => array(
103
            '5.1' => true,
104
            'alternative' => null,
105
        ),
106
        'mcrypt' => array(
107
            '7.1' => false,
108
            '7.2' => true,
109
            'alternative' => 'openssl (preferred) or pecl/mcrypt once available',
110
        ),
111
        'mcve' => array(
112
            '5.1' => true,
113
            'alternative' => 'pecl/mvce',
114
        ),
115
        'ming' => array(
116
            '5.3' => true,
117
            'alternative' => 'pecl/ming',
118
        ),
119
        'mnogosearch' => array(
120
            '5.1' => true,
121
            'alternative' => null,
122
        ),
123
        'msql' => array(
124
            '5.3' => true,
125
            'alternative' => null,
126
        ),
127
        'mssql' => array(
128
            '7.0' => true,
129
            'alternative' => null,
130
        ),
131
        'mysql_' => array(
132
            '5.5' => false,
133
            '7.0' => true,
134
            'alternative' => 'mysqli',
135
        ),
136
        'ncurses' => array(
137
            '5.3' => true,
138
            'alternative' => 'pecl/ncurses',
139
        ),
140
        'oracle' => array(
141
            '5.1' => true,
142
            'alternative' => 'oci8 or pdo_oci',
143
        ),
144
        'ovrimos' => array(
145
            '5.1' => true,
146
            'alternative' => null,
147
        ),
148
        'pfpro' => array(
149
            '5.3' => true,
150
            'alternative' => null,
151
        ),
152
        'sqlite' => array(
153
            '5.4' => true,
154
            'alternative' => null,
155
        ),
156
        // Has to be before `sybase` as otherwise it will never match.
157
        'sybase_ct' => array(
158
            '7.0' => true,
159
            'alternative' => null,
160
        ),
161
        'sybase' => array(
162
            '5.3' => true,
163
            'alternative' => 'sybase_ct',
164
        ),
165
        'w32api' => array(
166
            '5.1' => true,
167
            'alternative' => 'pecl/ffi',
168
        ),
169
        'yp' => array(
170
            '5.1' => true,
171
            'alternative' => null,
172
        ),
173
    );
174
175
    /**
176
     * Returns an array of tokens this test wants to listen for.
177
     *
178
     * @return array
179
     */
180
    public function register()
181
    {
182
        // Handle case-insensitivity of function names.
183
        $this->removedExtensions = $this->arrayKeysToLowercase($this->removedExtensions);
184
185
        return array(T_STRING);
186
187
    }//end register()
188
189
    /**
190
     * Processes this test, when one of its tokens is encountered.
191
     *
192
     * @param \PHP_CodeSniffer_File $phpcsFile The file being scanned.
193
     * @param int                   $stackPtr  The position of the current token in the
194
     *                                         stack passed in $tokens.
195
     *
196
     * @return void
197
     */
198
    public function process(\PHP_CodeSniffer_File $phpcsFile, $stackPtr)
0 ignored issues
show
Bug introduced by
The type PHP_CodeSniffer_File was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
199
    {
200
        $tokens = $phpcsFile->getTokens();
201
202
        // Find the next non-empty token.
203
        $openBracket = $phpcsFile->findNext(\PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 1), null, true);
0 ignored issues
show
Bug introduced by
The type PHP_CodeSniffer_Tokens was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
204
205
        if ($tokens[$openBracket]['code'] !== T_OPEN_PARENTHESIS) {
206
            // Not a function call.
207
            return;
208
        }
209
210
        if (isset($tokens[$openBracket]['parenthesis_closer']) === false) {
211
            // Not a function call.
212
            return;
213
        }
214
215
        // Find the previous non-empty token.
216
        $search   = \PHP_CodeSniffer_Tokens::$emptyTokens;
217
        $search[] = T_BITWISE_AND;
218
        $previous = $phpcsFile->findPrevious($search, ($stackPtr - 1), null, true);
219
        if ($tokens[$previous]['code'] === T_FUNCTION) {
220
            // It's a function definition, not a function call.
221
            return;
222
        }
223
224
        if ($tokens[$previous]['code'] === T_NEW) {
225
            // We are creating an object, not calling a function.
226
            return;
227
        }
228
229
        if ($tokens[$previous]['code'] === T_OBJECT_OPERATOR) {
230
            // We are calling a method of an object.
231
            return;
232
        }
233
234
        $function   = $tokens[$stackPtr]['content'];
235
        $functionLc = strtolower($function);
236
237
        if ($this->isWhiteListed($functionLc) === true) {
238
            // Function is whitelisted.
239
            return;
240
        }
241
242
        foreach ($this->removedExtensions as $extension => $versionList) {
243
            if (strpos($functionLc, $extension) === 0) {
244
                $itemInfo = array(
245
                    'name'   => $extension,
246
                );
247
                $this->handleFeature($phpcsFile, $stackPtr, $itemInfo);
248
                break;
249
            }
250
        }
251
252
    }//end process()
253
254
255
    /**
256
     * Is the current function being checked whitelisted ?
257
     *
258
     * Parsing the list late as it may be provided as a property, but also inline.
259
     *
260
     * @param string $content Content of the current token.
261
     *
262
     * @return bool
263
     */
264
    protected function isWhiteListed($content)
265
    {
266
        if (isset($this->functionWhitelist) === false) {
267
            return false;
268
        }
269
270
        if (is_string($this->functionWhitelist) === true) {
0 ignored issues
show
introduced by
The condition is_string($this->functionWhitelist) === true can never be true.
Loading history...
271
            if (strpos($this->functionWhitelist, ',') !== false) {
272
                $this->functionWhitelist = explode(',', $this->functionWhitelist);
273
            } else {
274
                $this->functionWhitelist = (array) $this->functionWhitelist;
275
            }
276
        }
277
278
        if (is_array($this->functionWhitelist) === true) {
0 ignored issues
show
introduced by
The condition is_array($this->functionWhitelist) === true can never be false.
Loading history...
279
            $this->functionWhitelist = array_map('strtolower', $this->functionWhitelist);
280
            return in_array($content, $this->functionWhitelist, true);
281
        }
282
283
        return false;
284
285
    }//end isWhiteListed()
286
287
288
    /**
289
     * Get the relevant sub-array for a specific item from a multi-dimensional array.
290
     *
291
     * @param array $itemInfo Base information about the item.
292
     *
293
     * @return array Version and other information about the item.
294
     */
295
    public function getItemArray(array $itemInfo)
296
    {
297
        return $this->removedExtensions[$itemInfo['name']];
298
    }
299
300
301
    /**
302
     * Get the error message template for this sniff.
303
     *
304
     * @return string
305
     */
306
    protected function getErrorMsgTemplate()
307
    {
308
        return "Extension '%s' is ";
309
    }
310
311
312
}//end class
313