Completed
Push — master ( a32632...c637b7 )
by Juliette
9s
created

PHPCompatibility_Sniffs_PHP_RemovedExtensionsSniff   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 286
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
wmc 17
lcom 1
cbo 3
dl 0
loc 286
rs 10
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A register() 0 8 1
B process() 0 55 9
B isWhiteListed() 0 21 5
A getItemArray() 0 4 1
A getErrorMsgTemplate() 0 4 1
1
<?php
2
/**
3
 * PHPCompatibility_Sniffs_PHP_RemovedExtensionsSniff.
4
 *
5
 * PHP version 5.4
6
 *
7
 * @category  PHP
8
 * @package   PHPCompatibility
9
 * @author    Wim Godden <[email protected]>
10
 * @copyright 2012 Cu.be Solutions bvba
11
 */
12
13
/**
14
 * PHPCompatibility_Sniffs_PHP_RemovedExtensionsSniff.
15
 *
16
 * Discourages the use of removed extensions. Suggests alternative extensions if available
17
 *
18
 * @category  PHP
19
 * @package   PHPCompatibility
20
 * @author    Wim Godden <[email protected]>
21
 * @copyright 2012 Cu.be Solutions bvba
22
 */
23
class PHPCompatibility_Sniffs_PHP_RemovedExtensionsSniff extends PHPCompatibility_AbstractRemovedFeatureSniff
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
24
{
25
    /**
26
     * A list of functions to whitelist, if any.
27
     *
28
     * This is intended for projects using functions which start with the same
29
     * prefix as one of the removed extensions.
30
     *
31
     * This property can be set from the ruleset, like so:
32
     * <rule ref="PHPCompatibility.PHP.RemovedExtensions">
33
     *   <properties>
34
     *     <property name="functionWhitelist" type="array" value="mysql_to_rfc3339,mysql_another_function" />
35
     *   </properties>
36
     * </rule>
37
     *
38
     * @var array
39
     */
40
    public $functionWhitelist;
41
42
    /**
43
     * A list of removed extensions with their alternative, if any
44
     *
45
     * The array lists : version number with false (deprecated) and true (removed).
46
     * If's sufficient to list the first version where the extension was deprecated/removed.
47
     *
48
     * @var array(string|null)
49
     */
50
    protected $removedExtensions = array(
51
        'activescript' => array(
52
                '5.1' => true,
53
                'alternative' => 'pecl/activescript'
54
        ),
55
        'cpdf' => array(
56
                '5.1' => true,
57
                'alternative' => 'pecl/pdflib'
58
        ),
59
        'dbase' => array(
60
                '5.3' => true,
61
                'alternative' => null
62
        ),
63
        'dbx' => array(
64
                '5.1' => true,
65
                'alternative' => 'pecl/dbx'
66
        ),
67
        'dio' => array(
68
                '5.1' => true,
69
                'alternative' => 'pecl/dio'
70
        ),
71
        'ereg' => array(
72
                '5.3' => false,
73
                '7.0' => true,
74
                'alternative' => 'pcre'
75
        ),
76
        'fam' => array(
77
                '5.1' => true,
78
                'alternative' => null
79
        ),
80
        'fbsql' => array(
81
                '5.3' => true,
82
                'alternative' => null
83
        ),
84
        'fdf' => array(
85
                '5.3' => true,
86
                'alternative' => 'pecl/fdf'
87
        ),
88
        'filepro' => array(
89
                '5.2' => true,
90
                'alternative' => null
91
        ),
92
        'hw_api' => array(
93
                '5.2' => true,
94
                'alternative' => null
95
        ),
96
        'ingres' => array(
97
                '5.1' => true,
98
                'alternative' => 'pecl/ingres'
99
        ),
100
        'ircg' => array(
101
                '5.1' => true,
102
                'alternative' => null
103
        ),
104
        'mcrypt' => array(
105
                '7.1' => false,
106
                'alternative' => 'openssl (preferred) or pecl/mcrypt once available'
107
        ),
108
        'mcve' => array(
109
                '5.1' => true,
110
                'alternative' => 'pecl/mvce'
111
        ),
112
        'ming' => array(
113
                '5.3' => true,
114
                'alternative' => 'pecl/ming'
115
        ),
116
        'mnogosearch' => array(
117
                '5.1' => true,
118
                'alternative' => null
119
        ),
120
        'msql' => array(
121
                '5.3' => true,
122
                'alternative' => null
123
        ),
124
        'mssql' => array(
125
                '7.0' => true,
126
                'alternative' => null
127
        ),
128
        'mysql_' => array(
129
                '5.5' => false,
130
                '7.0' => true,
131
                'alternative' => 'mysqli',
132
        ),
133
        'ncurses' => array(
134
                '5.3' => true,
135
                'alternative' => 'pecl/ncurses'
136
        ),
137
        'oracle' => array(
138
                '5.1' => true,
139
                'alternative' => 'oci8 or pdo_oci'
140
        ),
141
        'ovrimos' => array(
142
                '5.1' => true,
143
                'alternative' => null
144
        ),
145
        'pfpro' => array(
146
                '5.3' => true,
147
                'alternative' => null
148
        ),
149
        'sqlite' => array(
150
                '5.4' => true,
151
                'alternative' => null
152
        ),
153
        // Has to be before `sybase` as otherwise it will never match.
154
        'sybase_ct' => array(
155
                '7.0' => true,
156
                'alternative' => null
157
        ),
158
        'sybase' => array(
159
                '5.3' => true,
160
                'alternative' => 'sybase_ct'
161
        ),
162
        'w32api' => array(
163
                '5.1' => true,
164
                'alternative' => 'pecl/ffi'
165
        ),
166
        'yp' => array(
167
                '5.1' => true,
168
                'alternative' => null
169
        ),
170
    );
171
172
    /**
173
     * Returns an array of tokens this test wants to listen for.
174
     *
175
     * @return array
176
     */
177
    public function register()
178
    {
179
        // Handle case-insensitivity of function names.
180
        $this->removedExtensions = $this->arrayKeysToLowercase($this->removedExtensions);
181
182
        return array(T_STRING);
183
184
    }//end register()
185
186
    /**
187
     * Processes this test, when one of its tokens is encountered.
188
     *
189
     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
190
     * @param int                  $stackPtr  The position of the current token in the
191
     *                                        stack passed in $tokens.
192
     *
193
     * @return void
194
     */
195
    public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
196
    {
197
        $tokens = $phpcsFile->getTokens();
198
199
        // Find the next non-empty token.
200
        $openBracket = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 1), null, true);
201
202
        if ($tokens[$openBracket]['code'] !== T_OPEN_PARENTHESIS) {
203
            // Not a function call.
204
            return;
205
        }
206
207
        if (isset($tokens[$openBracket]['parenthesis_closer']) === false) {
208
            // Not a function call.
209
            return;
210
        }
211
212
        // Find the previous non-empty token.
213
        $search   = PHP_CodeSniffer_Tokens::$emptyTokens;
214
        $search[] = T_BITWISE_AND;
215
        $previous = $phpcsFile->findPrevious($search, ($stackPtr - 1), null, true);
216
        if ($tokens[$previous]['code'] === T_FUNCTION) {
217
            // It's a function definition, not a function call.
218
            return;
219
        }
220
221
        if ($tokens[$previous]['code'] === T_NEW) {
222
            // We are creating an object, not calling a function.
223
            return;
224
        }
225
226
        if ( $tokens[$previous]['code'] === T_OBJECT_OPERATOR ) {
227
            // We are calling a method of an object
228
            return;
229
        }
230
231
        $function   = $tokens[$stackPtr]['content'];
232
        $functionLc = strtolower($function);
233
234
        if($this->isWhiteListed($functionLc) === true){
235
            // Function is whitelisted.
236
            return;
237
        }
238
239
        foreach ($this->removedExtensions as $extension => $versionList) {
240
            if (strpos($functionLc, $extension) === 0) {
241
                $itemInfo = array(
242
                    'name'   => $extension,
243
                );
244
                $this->handleFeature($phpcsFile, $stackPtr, $itemInfo);
245
                break;
246
            }
247
        }
248
249
    }//end process()
250
251
252
    /**
253
     * Is the current function being checked whitelisted ?
254
     *
255
     * Parsing the list late as it may be provided as a property, but also inline.
256
     *
257
     * @param string $content Content of the current token.
258
     *
259
     * @return bool
260
     */
261
    protected function isWhiteListed($content) {
262
        if (isset($this->functionWhitelist) === false) {
263
            return false;
264
        }
265
266
        if (is_string($this->functionWhitelist) === true) {
267
            if (strpos($this->functionWhitelist, ',') !== false) {
268
                $this->functionWhitelist = explode(',', $this->functionWhitelist);
269
            } else {
270
                $this->functionWhitelist = (array) $this->functionWhitelist;
271
            }
272
        }
273
274
        if (is_array($this->functionWhitelist) === true) {
275
            $this->functionWhitelist = array_map('strtolower',$this->functionWhitelist);
276
            return in_array($content, $this->functionWhitelist, true);
277
        }
278
279
        return false;
280
281
    }//end isWhiteListed()
282
283
284
    /**
285
     * Get the relevant sub-array for a specific item from a multi-dimensional array.
286
     *
287
     * @param array $itemInfo Base information about the item.
288
     *
289
     * @return array Version and other information about the item.
290
     */
291
    public function getItemArray(array $itemInfo)
292
    {
293
        return $this->removedExtensions[$itemInfo['name']];
294
    }
295
296
297
    /**
298
     * Get the error message template for this sniff.
299
     *
300
     * @return string
301
     */
302
    protected function getErrorMsgTemplate()
303
    {
304
        return "Extension '%s' is ";
305
    }
306
307
308
}//end class
309