This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; |
||
3 | |||
4 | /** |
||
5 | * Our base class that we extend our other classes from |
||
6 | * |
||
7 | * It supplies some basic features as cross-linking with other classes |
||
8 | * after loading a newly created class. |
||
9 | **/ |
||
10 | class Base { |
||
11 | private $sError = ''; |
||
12 | private $sCronError = ''; |
||
13 | protected $table = ''; |
||
14 | private $values = array(), $types = ''; |
||
15 | |||
16 | public function getTableName() { |
||
17 | return $this->table; |
||
18 | } |
||
19 | |||
20 | protected $debug; |
||
21 | public function setDebug($debug) { |
||
22 | $this->debug = $debug; |
||
23 | } |
||
24 | public function setCoin($coin) { |
||
25 | $this->coin = $coin; |
||
0 ignored issues
–
show
|
|||
26 | } |
||
27 | public function setCoinAddress($coin_address) { |
||
28 | $this->coin_address = $coin_address; |
||
0 ignored issues
–
show
The property
coin_address does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
Loading history...
|
|||
29 | } |
||
30 | |||
31 | public $log; |
||
32 | public function setLog($log) { |
||
33 | $this->log = $log; |
||
34 | } |
||
35 | |||
36 | protected $mysqli; |
||
37 | public function setMysql($mysqli) { |
||
38 | $this->mysqli = $mysqli; |
||
39 | } |
||
40 | public function setMail($mail) { |
||
41 | $this->mail = $mail; |
||
0 ignored issues
–
show
The property
mail does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
Loading history...
|
|||
42 | } |
||
43 | public function setSalt($salt) { |
||
44 | $this->salt = $salt; |
||
0 ignored issues
–
show
The property
salt does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
Loading history...
|
|||
45 | } |
||
46 | public function setSalty($salt) { |
||
47 | $this->salty = $salt; |
||
0 ignored issues
–
show
The property
salty does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
Loading history...
|
|||
48 | } |
||
49 | /** |
||
50 | * @var Smarty |
||
51 | */ |
||
52 | var $smarty; |
||
53 | public function setSmarty($smarty) { |
||
54 | $this->smarty = $smarty; |
||
55 | } |
||
56 | public function setUser($user) { |
||
57 | $this->user = $user; |
||
0 ignored issues
–
show
The property
user does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
Loading history...
|
|||
58 | } |
||
59 | public function setSessionManager($session) { |
||
60 | $this->session = $session; |
||
0 ignored issues
–
show
The property
session does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
Loading history...
|
|||
61 | } |
||
62 | public function setConfig($config) { |
||
63 | $this->config = $config; |
||
0 ignored issues
–
show
The property
config does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
Loading history...
|
|||
64 | } |
||
65 | |||
66 | protected $aErrorCodes; |
||
67 | public function setErrorCodes(&$aErrorCodes) { |
||
68 | $this->aErrorCodes =& $aErrorCodes; |
||
69 | } |
||
70 | public function setToken($token) { |
||
71 | $this->token = $token; |
||
0 ignored issues
–
show
The property
token does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
Loading history...
|
|||
72 | } |
||
73 | public function setBlock($block) { |
||
74 | $this->block = $block; |
||
0 ignored issues
–
show
The property
block does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
Loading history...
|
|||
75 | } |
||
76 | public function setPayout($payout) { |
||
77 | $this->payout = $payout; |
||
0 ignored issues
–
show
The property
payout does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
Loading history...
|
|||
78 | } |
||
79 | public function setNotification($notification) { |
||
80 | $this->notification = $notification; |
||
0 ignored issues
–
show
The property
notification does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
Loading history...
|
|||
81 | } |
||
82 | public function setTransaction($transaction) { |
||
83 | $this->transaction = $transaction; |
||
0 ignored issues
–
show
The property
transaction does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
Loading history...
|
|||
84 | } |
||
85 | public function setMemcache($memcache) { |
||
86 | $this->memcache = $memcache; |
||
0 ignored issues
–
show
The property
memcache does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
Loading history...
|
|||
87 | } |
||
88 | public function setStatistics($statistics) { |
||
89 | $this->statistics = $statistics; |
||
0 ignored issues
–
show
The property
statistics does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
Loading history...
|
|||
90 | } |
||
91 | public function setSetting($setting) { |
||
92 | $this->setting = $setting; |
||
0 ignored issues
–
show
The property
setting does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
Loading history...
|
|||
93 | } |
||
94 | public function setTools($tools) { |
||
95 | $this->tools = $tools; |
||
0 ignored issues
–
show
The property
tools does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
Loading history...
|
|||
96 | } |
||
97 | public function setBitcoin($bitcoin) { |
||
98 | $this->bitcoin = $bitcoin; |
||
0 ignored issues
–
show
The property
bitcoin does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
Loading history...
|
|||
99 | } |
||
100 | public function setTokenType($tokentype) { |
||
101 | $this->tokentype = $tokentype; |
||
0 ignored issues
–
show
The property
tokentype does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
Loading history...
|
|||
102 | } |
||
103 | public function setCSRFToken($token) { |
||
104 | $this->CSRFToken = $token; |
||
0 ignored issues
–
show
The property
CSRFToken does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
Loading history...
|
|||
105 | } |
||
106 | public function setShare($share) { |
||
107 | $this->share = $share; |
||
0 ignored issues
–
show
The property
share does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
Loading history...
|
|||
108 | } |
||
109 | public function setErrorMessage($msg) { |
||
110 | $this->sError = $msg; |
||
111 | // Default to same error for crons |
||
112 | $this->sCronError = $msg; |
||
113 | } |
||
114 | public function setCronMessage($msg) { |
||
115 | // Used to overwrite any errors with a custom cron one |
||
116 | $this->sCronError = $msg; |
||
117 | } |
||
118 | public function getError() { |
||
119 | return $this->sError; |
||
120 | } |
||
121 | /** |
||
122 | * Additional information in error string for cronjobs logging |
||
123 | **/ |
||
124 | public function getCronError() { |
||
125 | return $this->sCronError; |
||
126 | } |
||
127 | |||
128 | /** |
||
129 | * Get error message from error code array |
||
130 | * @param errCode string Error code string |
||
131 | * @param optional string Optional addtitional error strings to append |
||
132 | * @retrun string Error Message |
||
133 | **/ |
||
134 | public function getErrorMsg($errCode='') { |
||
135 | if (!is_array($this->aErrorCodes)) return 'Error codes not loaded'; |
||
136 | if (!array_key_exists($errCode, $this->aErrorCodes)) return 'Unknown Error Code: ' . $errCode; |
||
137 | if (func_num_args() > 1) { |
||
138 | $args = func_get_args(); |
||
139 | array_shift($args); |
||
140 | $param_count = substr_count($this->aErrorCodes[$errCode], '%s'); |
||
141 | if ($param_count == count($args)) { |
||
142 | return vsprintf($this->aErrorCodes[$errCode], $args); |
||
143 | } else { |
||
144 | return $this->aErrorCodes[$errCode] . ' (missing information to complete string)'; |
||
145 | } |
||
146 | } else { |
||
147 | return $this->aErrorCodes[$errCode]; |
||
148 | } |
||
149 | } |
||
150 | |||
151 | /** |
||
152 | * Fetch count of all entries in table |
||
153 | * @param none |
||
154 | * @param data mixed Count or false |
||
155 | **/ |
||
156 | public function getCount() { |
||
157 | $this->debug->append("STA " . __METHOD__, 4); |
||
158 | $stmt = $this->mysqli->prepare("SELECT COUNT(id) AS count FROM $this->table"); |
||
159 | if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result()) |
||
160 | return $result->fetch_object()->count; |
||
161 | return $this->sqlError(); |
||
162 | } |
||
163 | |||
164 | /** |
||
165 | * Fetch count of all entries in table filtered by a column/value |
||
166 | * @param none |
||
167 | * @param data mixed Count or false |
||
168 | **/ |
||
169 | public function getCountFiltered($column='id', $value=NULL, $type='i', $operator = '=') { |
||
170 | $this->debug->append("STA " . __METHOD__, 4); |
||
171 | $stmt = $this->mysqli->prepare("SELECT COUNT(id) AS count FROM $this->table WHERE $column $operator ?"); |
||
172 | if ($this->checkStmt($stmt) && $stmt->bind_param($type, $value) && $stmt->execute() && $result = $stmt->get_result()) |
||
173 | return $result->fetch_object()->count; |
||
174 | return $this->sqlError(); |
||
175 | } |
||
176 | |||
177 | /** |
||
178 | * Fetch all entries as an assoc array from a table |
||
179 | * This should, in general, not be used but sometimes it's just easier |
||
180 | * @param none |
||
181 | * @return array Assoc array of all rows found in table |
||
182 | **/ |
||
183 | View Code Duplication | public function getAllAssoc() { |
|
184 | $this->debug->append("STA " . __METHOD__, 4); |
||
185 | $stmt = $this->mysqli->prepare("SELECT * FROM $this->table"); |
||
186 | if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result()) |
||
187 | return $result->fetch_all(MYSQLI_ASSOC); |
||
188 | return $this->sqlError(); |
||
0 ignored issues
–
show
The return type of
return $this->sqlError(); (boolean ) is incompatible with the return type documented by Base::getAllAssoc of type array .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return 'Johannes';
}
}
class BlogPost extends Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function
Loading history...
|
|||
189 | } |
||
190 | |||
191 | /** |
||
192 | * Get a single row as an assoc array |
||
193 | * @param value string Value to search for |
||
194 | * @param field string Column to search for |
||
195 | * @param type string Type of value |
||
196 | * @return array Resulting row |
||
197 | **/ |
||
198 | protected function getSingleAssoc($value, $field='id', $type='i') { |
||
199 | $this->debug->append("STA " . __METHOD__, 4); |
||
200 | $stmt = $this->mysqli->prepare("SELECT * FROM $this->table WHERE $field = ? LIMIT 1"); |
||
201 | if ($this->checkStmt($stmt) && $stmt->bind_param($type, $value) && $stmt->execute() && $result = $stmt->get_result()) |
||
202 | return $result->fetch_assoc(); |
||
203 | return false; |
||
0 ignored issues
–
show
The return type of
return false; (false ) is incompatible with the return type documented by Base::getSingleAssoc of type array .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return 'Johannes';
}
}
class BlogPost extends Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function
Loading history...
|
|||
204 | } |
||
205 | |||
206 | /** |
||
207 | * Get a single value from a row matching the query specified |
||
208 | * @param value string Value to search for |
||
209 | * @param search Return column to search for |
||
210 | * @param field string Search column |
||
211 | * @param type string Type of value |
||
212 | * @param lower bool try with LOWER comparision |
||
213 | * @return array Return result |
||
214 | **/ |
||
215 | protected function getSingle($value, $search='id', $field='id', $type="i", $lower=false) { |
||
216 | $this->debug->append("STA " . __METHOD__, 4); |
||
217 | $sql = "SELECT $search FROM $this->table WHERE"; |
||
218 | $lower ? $sql .= " LOWER($field) = LOWER(?)" : $sql .= " $field = ?"; |
||
219 | $sql .= " LIMIT 1"; |
||
220 | $stmt = $this->mysqli->prepare($sql); |
||
221 | if ($this->checkStmt($stmt)) { |
||
222 | $stmt->bind_param($type, $value); |
||
223 | $stmt->execute(); |
||
224 | $stmt->bind_result($retval); |
||
0 ignored issues
–
show
|
|||
225 | $stmt->fetch(); |
||
226 | $stmt->close(); |
||
227 | return $retval; |
||
228 | } |
||
229 | return false; |
||
0 ignored issues
–
show
The return type of
return false; (false ) is incompatible with the return type documented by Base::getSingle of type array .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return 'Johannes';
}
}
class BlogPost extends Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function
Loading history...
|
|||
230 | } |
||
231 | |||
232 | /** |
||
233 | * Check if the prepared statement is valid |
||
234 | * @param $bState Statement return value |
||
235 | * @return bool true or false |
||
236 | **/ |
||
237 | function checkStmt($bState) { |
||
238 | $this->debug->append("STA " . __METHOD__, 4); |
||
239 | if ($bState ===! true) |
||
240 | return $this->sqlError(); |
||
241 | return true; |
||
242 | } |
||
243 | |||
244 | /** |
||
245 | * Catch SQL errors with this method |
||
246 | * @param error_code string Error code to read |
||
247 | **/ |
||
248 | protected function sqlError($error_code='E0020') { |
||
249 | // More human-readable error for UI |
||
250 | if (func_num_args() == 0) { |
||
251 | $this->setErrorMessage($this->getErrorMsg($error_code)); |
||
252 | } else { |
||
253 | $this->setErrorMessage(call_user_func_array(array($this, 'getErrorMsg'), func_get_args())); |
||
254 | } |
||
255 | // Default to SQL error for debug and cron errors |
||
256 | $this->debug->append($this->getErrorMsg('E0019', $this->mysqli->lastused->errno)); |
||
257 | $this->setCronMessage($this->getErrorMsg('E0019', $this->mysqli->lastused->errno)); |
||
258 | |||
259 | return false; |
||
260 | } |
||
261 | |||
262 | /** |
||
263 | * @param userID int Account ID |
||
264 | * Update a single row in a table |
||
265 | * @param field string Field to update |
||
266 | * @return bool |
||
267 | **/ |
||
268 | protected function updateSingle($id, $field, $table='') { |
||
269 | if (empty($table)) $table = $this->table; |
||
270 | $this->debug->append("STA " . __METHOD__, 4); |
||
271 | $stmt = $this->mysqli->prepare("UPDATE $table SET " . $field['name'] . " = ? WHERE id = ? LIMIT 1"); |
||
272 | if ($this->checkStmt($stmt) && $stmt->bind_param($field['type'].'i', $field['value'], $id) && $stmt->execute()) |
||
273 | return true; |
||
274 | $this->debug->append("Unable to update " . $field['name'] . " with " . $field['value'] . " for ID $id"); |
||
275 | return $this->sqlError(); |
||
276 | } |
||
277 | |||
278 | /** |
||
279 | * We may need to generate our bind_param list |
||
280 | **/ |
||
281 | public function addParam($type, &$value) { |
||
282 | $this->values[] = $value; |
||
283 | $this->types .= $type; |
||
284 | } |
||
285 | public function getParam() { |
||
286 | $array = array_merge(array($this->types), $this->values); |
||
287 | // Clear the data |
||
288 | $this->values = NULL; |
||
289 | $this->types = NULL; |
||
290 | // See here why we need this: http://stackoverflow.com/questions/16120822/mysqli-bind-param-expected-to-be-a-reference-value-given |
||
291 | if (strnatcmp(phpversion(),'5.3') >= 0) { |
||
292 | $refs = array(); |
||
293 | foreach($array as $key => $value) |
||
294 | $refs[$key] = &$array[$key]; |
||
295 | return $refs; |
||
296 | } |
||
297 | return $array; |
||
298 | } |
||
299 | } |
||
300 |
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: