Issues (493)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

lib/backend/database.php (34 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * ownCloud - Database backend for Contacts
4
 *
5
 * @author Thomas Tanghus
6
 * @copyright 2013-2014 Thomas Tanghus ([email protected])
7
 *
8
 * This library is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
10
 * License as published by the Free Software Foundation; either
11
 * version 3 of the License, or any later version.
12
 *
13
 * This library is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
17
 *
18
 * You should have received a copy of the GNU Affero General Public
19
 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
20
 *
21
 */
22
23
namespace OCA\Contacts\Backend;
24
25
use OCA\Contacts\Contact;
26
use OCA\Contacts\VObject\VCard;
27
use OCA\Contacts\Utils\Properties;
28
use Sabre\VObject\Reader;
29
30
/**
31
 * Backend class for a users own contacts.
32
 */
33
34
class Database extends AbstractBackend {
35
36
	static private $preparedQueries = array();
37
38
	/**
39
	 * The name of the backend.
40
	 *
41
	 * @var string
42
	 */
43
	public $name = 'local';
44
45
	/**
46
	 * The cached address books.
47
	 *
48
	 * @var array[]
49
	 */
50
	public $addressBooks;
51
52
	/**
53
	 * The table that holds the address books.
54
	 *
55
	 * @var string
56
	 */
57
	public $addressBooksTableName;
58
59
	/**
60
	 * The table that holds the contact vCards.
61
	 *
62
	 * @var string
63
	 */
64
	public $cardsTableName;
65
66
	/**
67
	 * The table that holds the indexed vCard properties.
68
	 *
69
	 * @var string
70
	 */
71
	public $indexTableName;
72
73
	/**
74
	* Sets up the backend
75
	*
76
	*/
77 2
	public function __construct(
78
		$userid = null,
79
		$options = array(
80
			'addressBooksTableName' => '*PREFIX*contacts_addressbooks',
81
			'cardsTableName' => '*PREFIX*contacts_cards',
82
			'indexTableName' => '*PREFIX*contacts_cards_properties'
83
		)
84
	) {
85 2
		$this->userid = $userid ? $userid : \OCP\User::getUser();
86 2
		$this->addressBooksTableName = $options['addressBooksTableName'];
87 2
		$this->cardsTableName = $options['cardsTableName'];
88 2
		$this->indexTableName = $options['indexTableName'];
89 2
		$this->addressBooks = array();
90 2
	}
91
92
	/**
93
	* {@inheritdoc}
94
	*/
95
	public function getAddressBooksForUser(array $options = array()) {
96
97
		try {
98
			$result = $this->getPreparedQuery('getaddressbooksforuser')
99
				->execute(array($this->userid));
100
101 View Code Duplication
			if (\OCP\DB::isError($result)) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
102
				\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: '
103
					. \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
104
				return $this->addressBooks;
105
			}
106
107
		} catch(\Exception $e) {
108
			\OCP\Util::writeLog('contacts', __METHOD__.' exception: '
109
				. $e->getMessage(), \OCP\Util::ERROR);
110
			return $this->addressBooks;
111
		}
112
113
		while ($row = $result->fetchRow()) {
114
			$row['permissions'] = \OCP\PERMISSION_ALL;
115
			$this->addressBooks[$row['id']] = $row;
116
		}
117
118
		// Create default address book if the list is empty
119
		if (count($this->addressBooks) === 0) {
120
			$l10n = \OCP\Util::getL10N('contacts');
121
			$id = $this->createAddressBook(array('displayname' => $l10n->t('Contacts')));
122
			if ($id !== false) {
123
				$addressBook = $this->getAddressBook($id);
124
				$this->addressBooks[$id] = $addressBook;
125
			} else {
126
				\OCP\Util::writeLog(
127
					'contacts',
128
					__METHOD__ . ', Error creating default address book',
129
					\OCP\Util::ERROR
130
				);
131
			}
132
		}
133
134
		return $this->addressBooks;
135
	}
136
137
	/**
138
	* {@inheritdoc}
139
	*/
140 2
	public function getAddressBook($addressBookId, array $options = array()) {
141 2
		$owner = isset($options['shared_by']) ? $options['shared_by'] : $this->userid;
142
		//\OCP\Util::writeLog('contacts', __METHOD__.' id: '
143
		//	. $addressBookId, \OCP\Util::DEBUG);
144 2
		if ($this->addressBooks && isset($this->addressBooks[$addressBookId])) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->addressBooks of type array[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
145
			//print(__METHOD__ . ' ' . __LINE__ .' addressBookInfo: ' . print_r($this->addressBooks[$addressBookId], true));
146
			return $this->addressBooks[$addressBookId];
147
		}
148
149
		// Hmm, not found. Lets query the db.
150
		try {
151 2
			$result = $this->getPreparedQuery('getaddressbook')->execute(array($addressBookId, $owner));
152
153 2 View Code Duplication
			if (\OCP\DB::isError($result)) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
154
				\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: '
155
					. \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
156
				return null;
157
			}
158
159 2
			$row = $result->fetchRow();
160
161 2
			if (!$row) {
162
				return null;
163
			}
164
165 2
			$row['permissions'] = \OCP\PERMISSION_ALL;
166 2
			$row['backend'] = $this->name;
167 2
			$this->addressBooks[$addressBookId] = $row;
168 2
			return $row;
169
170
		} catch(\Exception $e) {
171
			\OCP\Util::writeLog('contacts', __METHOD__.' exception: '
172
				. $e->getMessage(), \OCP\Util::ERROR);
173
			return null;
174
		}
175
176
	}
177
178
	/**
179
	* {@inheritdoc}
180
	* @param string|false $addressBookId
181
	*/
182
	public function hasAddressBook($addressBookId) {
183
184
		// First check if it's already cached
185
		if ($this->addressBooks && isset($this->addressBooks[$addressBookId])) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->addressBooks of type array[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
186
			return true;
187
		}
188
189
		return count($this->getAddressBook($addressBookId)) > 0;
0 ignored issues
show
It seems like $addressBookId defined by parameter $addressBookId on line 182 can also be of type false; however, OCA\Contacts\Backend\Database::getAddressBook() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
190
	}
191
192
	/**
193
	 * Updates an addressbook's properties
194
	 *
195
	 * @param string $addressBookId
196
	 * @param array $changes
197
	 * @return bool
198
	 */
199 2
	public function updateAddressBook($addressBookId, array $changes) {
200
201
		if (count($changes) === 0) {
202
			return false;
203
		}
204
205
		$query = 'UPDATE `' . $this->addressBooksTableName . '` SET ';
206
207
		$updates = array();
208
209 View Code Duplication
		if (isset($changes['displayname'])) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
210
			$query .= '`displayname` = ?, ';
211
			$updates[] = $changes['displayname'];
212
213
			if ($this->addressBooks && isset($this->addressBooks[$addressBookId])) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->addressBooks of type array[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
214
				$this->addressBooks[$addressBookId]['displayname'] = $changes['displayname'];
215
			}
216
217
		}
218
219 View Code Duplication
		if (isset($changes['description'])) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
220
221
			$query .= '`description` = ?, ';
222
			$updates[] = $changes['description'];
223
224
			if ($this->addressBooks && isset($this->addressBooks[$addressBookId])) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->addressBooks of type array[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
225
				$this->addressBooks[$addressBookId]['description'] = $changes['description'];
226
			}
227
228
		}
229
230
		$query .= '`ctag` = ? + 1 WHERE `id` = ?';
231
		$now = time();
232
		$updates[] = $now;
233
		$updates[] = $addressBookId;
234
235 View Code Duplication
		if ($this->addressBooks && isset($this->addressBooks[$addressBookId])) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->addressBooks of type array[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
236
			$this->addressBooks[$addressBookId]['lastmodified'] = $now;
237
		}
238
239
		try {
240
241
			$stmt = \OCP\DB::prepare($query);
242
			$result = $stmt->execute($updates);
243
244 View Code Duplication
			if (\OCP\DB::isError($result)) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
245
				\OCP\Util::writeLog('contacts',
246 2
					__METHOD__. 'DB error: '
247
					. \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
248
				return false;
249
			}
250
251
		} catch(\Exception $e) {
252
			\OCP\Util::writeLog('contacts',
253
				__METHOD__ . ', exception: '
254
				. $e->getMessage(), \OCP\Util::ERROR);
255
			return false;
256
		}
257
258
		return true;
259
	}
260
261
	/**
262
	 * Creates a new address book
263
	 *
264
	 * Supported properties are 'displayname', 'description' and 'uri'.
265
	 * 'uri' is supported to allow to add from CardDAV requests, and MUST
266
	 * be used for the 'uri' database field if present.
267
	 * 'displayname' MUST be present.
268
	 *
269
	 * @param array $properties
270
	 * @return string|false The ID if the newly created AddressBook or false on error.
271
	 */
272 2
	public function createAddressBook(array $properties) {
273
274 2
		if (count($properties) === 0 || !isset($properties['displayname'])) {
275
			return false;
276 2
		}
277
278 2
		$updates = array($this->userid, $properties['displayname']);
279 2
		$updates[] = isset($properties['uri'])
280 2
			? $properties['uri']
281 2
			: $this->createAddressBookURI($properties['displayname']);
282 2
		$updates[] = isset($properties['description']) ? $properties['description'] : '';
283 2
		$ctag = time();
284 2
		$updates[] = $ctag;
285
286
		try {
287 2
			$result = $this->getPreparedQuery('createaddressbook')->execute($updates);
288
289 2 View Code Duplication
			if (\OCP\DB::isError($result)) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
290
				\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
291
				return false;
292
			}
293
294 2
		} catch(\Exception $e) {
295
			\OCP\Util::writeLog('contacts', __METHOD__ . ', exception: ' . $e->getMessage(), \OCP\Util::ERROR);
296
			return false;
297
		}
298
299 2
		$newid = \OCP\DB::insertid($this->addressBooksTableName);
300
301 2
		if ($this->addressBooks) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->addressBooks of type array[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
302
			$updates['id'] = $newid;
303
			$updates['ctag'] = $ctag;
304
			$updates['lastmodified'] = $ctag;
305
			$updates['permissions'] = \OCP\PERMISSION_ALL;
306
			$this->addressBooks[$newid] = $updates;
307
		}
308
309 2
		return $newid;
310
	}
311
312
	/**
313
	 * Get all contact ids from the address book to run pre_deleteAddressBook hook
314
	 *
315
	 * @param string $addressBookId
316
	 */
317 2
	protected function preDeleteAddressBook($addressBookId) {
318
		// Get all contact ids for this address book
319
		$ids = array();
320
		$result = null;
321
322
		try {
323
324
			$result = $this->getPreparedQuery('getcontactids')
325
				->execute(array($addressBookId));
326
327 View Code Duplication
			if (\OCP\DB::isError($result)) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
328
				\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: '
329
					. \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
330
				return false;
331
			}
332
333
		} catch(\Exception $e) {
334
			\OCP\Util::writeLog('contacts', __METHOD__.
335 2
				', exception: ' . $e->getMessage(), \OCP\Util::ERROR);
336
			return false;
337
		}
338
339
		if (!is_null($result)) {
340
			while ($id = $result->fetchOne()) {
341
				$ids[] = $id;
342 2
			}
343
344
			\OCP\Util::emitHook('OCA\Contacts', 'pre_deleteAddressBook',
345
				array('addressbookid' => $addressBookId, 'contactids' => $ids)
346
			);
347
		}
348
	}
349
350
	/**
351
	 * Deletes an entire addressbook and all its contents
352
	 *
353
	 * NOTE: For efficience this method bypasses the cleanup hooks and deletes
354
	 * property indexes and category/group relations by itself.
355
	 *
356
	 * @param string $addressBookId
357
	 * @return bool
358
	 */
359
	public function deleteAddressBook($addressBookId) {
360
361
		$this->preDeleteAddressBook($addressBookId);
362
363
		try {
364
			$this->getPreparedQuery('deleteaddressbookcontacts')
365
				->execute(array($addressBookId));
366
		} catch(\Exception $e) {
367
			\OCP\Util::writeLog('contacts', __METHOD__.
368
				', exception: ' . $e->getMessage(), \OCP\Util::ERROR);
369
			return false;
370
		}
371
372
		try {
373
			$this->getPreparedQuery('deleteaddressbook')
374
				->execute(array($addressBookId));
375
		} catch(\Exception $e) {
376
			\OCP\Util::writeLog('contacts', __METHOD__.
377
				', exception: ' . $e->getMessage(), \OCP\Util::ERROR);
378
			return false;
379
		}
380
381
		if ($this->addressBooks && isset($this->addressBooks[$addressBookId])) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->addressBooks of type array[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
382
			unset($this->addressBooks[$addressBookId]);
383
		}
384
385
		return true;
386
	}
387
388
	/**
389
	 * @brief Updates ctag for addressbook
390
	 * @param integer $id
391
	 * @return boolean
392
	 */
393 2
	public function setModifiedAddressBook($id) {
394 2
		$ctag = time();
395 2
		$this->getPreparedQuery('touchaddressbook')->execute(array($ctag, $id));
396
397 2
		return true;
398
	}
399
400
	/**
401
	* {@inheritdoc}
402
	*/
403 2
	public function lastModifiedAddressBook($addressBookId) {
404
405 2 View Code Duplication
		if ($this->addressBooks && isset($this->addressBooks[$addressBookId])) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->addressBooks of type array[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
406 2
			return $this->addressBooks[$addressBookId]['lastmodified'];
407
		}
408
409
		$addressBook = $this->getAddressBook($addressBookId);
410
		if($addressBook) {
411
			$this->addressBooks[$addressBookId] = $addressBook;
412
		}
413
		return $addressBook ? $addressBook['lastmodified'] : null;
414
	}
415
416
	/**
417
	 * Returns the number of contacts in a specific address book.
418
	 *
419
	 * @param string $addressBookId
420
	 * @return null|integer
421
	 */
422
	public function numContacts($addressBookId) {
423
424
		$result = $this->getPreparedQuery('numcontacts')->execute(array($addressBookId));
425
426 View Code Duplication
		if (\OCP\DB::isError($result)) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
427
			\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
428
			return null;
429
		}
430
431
		return (int)$result->fetchOne();
432
	}
433
434
	/**
435
	* {@inheritdoc}
436
	*/
437
	public function getContacts($addressBookId, array $options = array()) {
438
		//\OCP\Util::writeLog('contacts', __METHOD__.' addressbookid: ' . $addressBookId, \OCP\Util::DEBUG);
439
		$cards = array();
440
		try {
441
			$queryIdentifier = (isset($options['omitdata']) && $options['omitdata'] === true)
442
				? 'getcontactsomitdata'
443
				: 'getcontacts';
444
445
			$result = $this->getPreparedQuery($queryIdentifier, $options)->execute(array($addressBookId));
446
447 View Code Duplication
			if (\OCP\DB::isError($result)) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
448
				\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
449
				return $cards;
450
			}
451
452
		} catch(\Exception $e) {
453
			\OCP\Util::writeLog('contacts', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::ERROR);
454
			return $cards;
455
		}
456
457
		if (!is_null($result)) {
458
459
			while ($row = $result->fetchRow()) {
460
				$row['permissions'] = \OCP\PERMISSION_ALL;
461
				$cards[] = $row;
462
			}
463
464
		}
465
466
		return $cards;
467
	}
468
469
	/**
470
	 * Returns a specific contact.
471
	 *
472
	 * NOTE: The contact $id for Database and Shared backends can be an array containing
473
	 * either 'id' or 'uri' to be able to play seamlessly with the
474
	 * CardDAV backend.
475
	 * NOTE: $addressbookid isn't always used in the query, so there's no access control.
476
	 * 	This is because the groups backend - \OCP\Tags - doesn't no about parent collections
477
	 * 	only object IDs. Hence a hack is made with an optional 'noCollection'.
478
	 *
479
	 * @param string $addressBookId
480
	 * @param string|array $id Contact ID
481
	 * @param array $options - Optional (backend specific options)
482
	 * @return array|null
483
	 */
484 2
	public function getContact($addressBookId, $id, array $options = array()) {
485
		//\OCP\Util::writeLog('contacts', __METHOD__.' identifier: ' . $addressBookId . ' / ' . $id, \OCP\Util::DEBUG);
486
487
		// When dealing with tags we have no idea if which address book it's in
488
		// but since they're all in the same table they have unique IDs anyway
489 2
		$noCollection = isset($options['noCollection']) ? $options['noCollection'] : false;
490
491 2
		$queryIdentifier = 'getcontact';
492 2
		$queries = array();
493
494
		// When querying from CardDAV we don't have the ID, only the uri
495 2
		if (is_array($id)) {
496
			if (isset($id['id'])) {
497
				$queries[] = $id['id'];
498
				$queryIdentifier .= 'byid';
499
			} elseif (isset($id['uri'])) {
500
				$queries[] = $id['uri'];
501
				$queryIdentifier .= 'byuri';
502
			} else {
503
				throw new \Exception(
504
					__METHOD__ . ' If second argument is an array, either \'id\' or \'uri\' has to be set.'
505
				);
506
			}
507
		} else {
508 2
			if (!trim($id)) {
509
				throw new \Exception(
510
					__METHOD__ . ' Missing or empty second argument \'$id\'.'
511
				);
512
			}
513 2
			$queries[] = $id;
514 2
			$queryIdentifier .= 'byid';
515
		}
516
517 2
		if ($noCollection) {
518
			$queryIdentifier .= 'nocollection';
519
		} else {
520 2
			$queries[] = $addressBookId;
521
		}
522
523
		try {
524
			//\OCP\Util::writeLog('contacts', __METHOD__.', identifier: '. $queryIdentifier . ', queries: ' . implode(',', $queries), \OCP\Util::DEBUG);
525 2
			$result = $this->getPreparedQuery($queryIdentifier)->execute($queries);
526
527 2 View Code Duplication
			if (\OCP\DB::isError($result)) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
528
				\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
529
				return null;
530
			}
531
532 2
		} catch (\Exception $e) {
533
			\OCP\Util::writeLog('contacts', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::ERROR);
534
			\OCP\Util::writeLog('contacts', __METHOD__.', id: '. $id, \OCP\Util::DEBUG);
535
			return null;
536
		}
537
538 2
		$row = $result->fetchRow();
539
540 2
		if (!$row) {
541
			if (is_array($id)) {
542
				$idstr = implode(", ", $id);
543
			} else {
544
				$idstr = $id;
545
			}
546
			\OCP\Util::writeLog('contacts', __METHOD__.', Not found, id: '. $idstr, \OCP\Util::DEBUG);
547
			return null;
548
		}
549
550 2
		$row['permissions'] = \OCP\PERMISSION_ALL;
551 2
		return $row;
552
	}
553
554
	/**
555
	 * @param string|false $addressBookId
556
	 * @param false|string $id
557
	 */
558
	public function hasContact($addressBookId, $id) {
559
		try {
560
			return $this->getContact($addressBookId, $id) !== null;
0 ignored issues
show
It seems like $addressBookId defined by parameter $addressBookId on line 558 can also be of type false; however, OCA\Contacts\Backend\Database::getContact() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
It seems like $id defined by parameter $id on line 558 can also be of type false; however, OCA\Contacts\Backend\Database::getContact() does only seem to accept string|array, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
561
		} catch (\Exception $e) {
562
			\OCP\Util::writeLog('contacts', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::ERROR);
563
			return false;
564
		}
565
	}
566
567
	/**
568
	 * Creates a new contact
569
	 *
570
	 * In the Database and Shared backends contact be either a Contact object or a string
571
	 * with carddata to be able to play seamlessly with the CardDAV backend.
572
	 * If this method is called by the CardDAV backend, the carddata is already validated.
573
	 * NOTE: It's assumed that this method is called either from the CardDAV backend, the
574
	 * import script, or from the ownCloud web UI in which case either the uri parameter is
575
	 * set, or the contact has a UID. If neither is set, it will fail.
576
	 *
577
	 * @param string $addressBookId
578
	 * @param string $contact
579
	 * @param array $options - Optional (backend specific options)
580
	 * @return false|string The identifier for the new contact or false on error.
581
	 */
582 2
	public function createContact($addressBookId, $contact, array $options = array()) {
583
		//\OCP\Util::writeLog('contacts', __METHOD__.' addressBookId: ' . $addressBookId, \OCP\Util::DEBUG);
584
585 2
		$uri = isset($options['uri']) ? $options['uri'] : null;
586
587 2 View Code Duplication
		if (!$contact instanceof VCard) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
588
			try {
589
				$contact = Reader::read($contact);
590
			} catch(\Exception $e) {
591
				\OCP\Util::writeLog('contacts', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::ERROR);
592
				return false;
593
			}
594
		}
595
596
		try {
597 2
			$contact->validate(VCard::REPAIR|VCard::UPGRADE);
0 ignored issues
show
It seems like $contact is not always an object, but can also be of type null. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
598 2
		} catch (\Exception $e) {
599
			\OCP\Util::writeLog('contacts', __METHOD__ . ' ' .
600
				'Error validating vcard: ' . $e->getMessage(), \OCP\Util::ERROR);
601
			return false;
602
		}
603
604 2
		$uri = is_null($uri) ? $this->uniqueURI($addressBookId, $contact->UID . '.vcf') : $uri;
605 2
		$now = new \DateTime;
606 2
		$contact->REV = $now->format(\DateTime::W3C);
607
608 2
		$appinfo = \OCP\App::getAppInfo('contacts');
609 2
		$appversion = \OCP\App::getAppVersion('contacts');
610 2
		$prodid = '-//ownCloud//NONSGML ' . $appinfo['name'] . ' ' . $appversion.'//EN';
611 2
		$contact->PRODID = $prodid;
612
613
		try {
614 2
			$result = $this->getPreparedQuery('createcontact')
615 2
				->execute(
616
					array(
617 2
						$addressBookId,
618 2
						(string)$contact->FN,
619 2
						$contact->serialize(),
620 2
						$uri,
621 2
						time()
622 2
					)
623 2
				);
624
625 2 View Code Duplication
			if (\OCP\DB::isError($result)) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
626
				\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
627
				return false;
628
			}
629
630 2
		} catch(\Exception $e) {
631
			\OCP\Util::writeLog('contacts', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::ERROR);
632
			return false;
633
		}
634 2
		$newid = \OCP\DB::insertid($this->cardsTableName);
635
636 2
		$this->setModifiedAddressBook($addressBookId);
637 2
		\OCP\Util::emitHook('OCA\Contacts', 'post_createContact',
638 2
			array('id' => $newid, 'addressBookId' => $addressBookId, 'backend' => $this->name, 'contact' => $contact)
639 2
		);
640 2
		return (string)$newid;
641
	}
642
643
	/**
644
	 * Updates a contact
645
	 *
646
	 * @param string $addressBookId
647
	 * @param false|string $id Contact ID
648
	 * @param string $contact
649
	 * @param array $options - Optional (backend specific options)
650
	 * @see getContact
651
	 * @return bool
652
	 * @throws \Exception if $contact is a string but can't be parsed as a VCard
653
	 * @throws \Exception if the Contact to update couldn't be found
654
	 */
655
	public function updateContact($addressBookId, $id, $contact, array $options = array()) {
656
		//\OCP\Util::writeLog('contacts', __METHOD__.' identifier: ' . $addressBookId . ' / ' . $id, \OCP\Util::DEBUG);
657
		$noCollection = isset($options['noCollection']) ? $options['noCollection'] : false;
658
		$isBatch = isset($options['isBatch']) ? $options['isBatch'] : false;
659
660
		$updateRevision = true;
661
		$isCardDAV = false;
662
663 View Code Duplication
		if (!$contact instanceof VCard) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
664
			try {
665
				$contact = Reader::read($contact);
666
			} catch(\Exception $e) {
667
				\OCP\Util::writeLog('contacts', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::ERROR);
668
				return false;
669
			}
670
		}
671
672
		if (is_array($id)) {
673
674
			if (isset($id['id'])) {
675
				$id = $id['id'];
676
			} elseif (isset($id['uri'])) {
677
				$updateRevision = false;
678
				$isCardDAV = true;
679
				$id = $this->getIdFromUri($addressBookId,$id['uri']);
680
681
				if (is_null($id)) {
682
					\OCP\Util::writeLog('contacts', __METHOD__ . ' Couldn\'t find contact', \OCP\Util::ERROR);
683
					return false;
684
				}
685
686
			} else {
687
				throw new \Exception(
688
					__METHOD__ . ' If second argument is an array, either \'id\' or \'uri\' has to be set.'
689
				);
690
			}
691
		}
692
693
		if ($updateRevision || !isset($contact->REV)) {
694
			$now = new \DateTime;
695
			$contact->REV = $now->format(\DateTime::W3C);
696
		}
697
698
		$data = $contact->serialize();
699
700
		if ($noCollection) {
701
			$me = $this->getContact(null, $id, $options);
702
			$addressBookId = $me['parent'];
703
		}
704
705
		$updates = array($contact->FN, $data, time(), $id, $addressBookId);
706
707
		try {
708
709
			$result = $this->getPreparedQuery('updatecontact')->execute($updates);
710
711 View Code Duplication
			if (\OCP\DB::isError($result)) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
712
				\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
713
				return false;
714
			}
715
716
		} catch(\Exception $e) {
717
			\OCP\Util::writeLog('contacts', __METHOD__.', exception: '
718
				. $e->getMessage(), \OCP\Util::ERROR);
719
			\OCP\Util::writeLog('contacts', __METHOD__.', id' . $id, \OCP\Util::DEBUG);
720
			return false;
721
		}
722
723
		$this->setModifiedAddressBook($addressBookId);
724
725
		if (!$isBatch) {
726
727
			\OCP\Util::emitHook('OCA\Contacts', 'post_updateContact',
728
				array(
729
					'backend' => $this->name,
730
					'addressBookId' => $addressBookId,
731
					'contactId' => $id,
732
					'contact' => $contact,
733
					'carddav' => $isCardDAV
734
				)
735
			);
736
737
		}
738
739
		return true;
740
	}
741
742
	/**
743
	 * Deletes a contact
744
	 *
745
	 * @param string $addressBookId
746
	 * @param false|string $id
747
	 * @param array $options - Optional (backend specific options)
748
	 * @see getContact
749
	 * @return bool
750
	 */
751
	public function deleteContact($addressBookId, $id, array $options = array()) {
752
		// TODO: pass the uri in $options instead.
753
754
		$noCollection = isset($options['noCollection']) ? $options['noCollection'] : false;
755
		$isBatch = isset($options['isBatch']) ? $options['isBatch'] : false;
756
757
		if (is_array($id)) {
758
759
			if (isset($id['id'])) {
760
				$id = $id['id'];
761
			} elseif (isset($id['uri'])) {
762
763
				$id = $this->getIdFromUri($addressBookId,$id['uri']);
764
765
				if (is_null($id)) {
766
					\OCP\Util::writeLog('contacts', __METHOD__ . ' Couldn\'t find contact', \OCP\Util::ERROR);
767
					return false;
768
				}
769
770
			} else {
771
				throw new \Exception(
772
					__METHOD__ . ' If second argument is an array, either \'id\' or \'uri\' has to be set.'
773
				);
774
			}
775
		}
776
777
		if (!$isBatch) {
778
			\OCP\Util::emitHook('OCA\Contacts', 'pre_deleteContact',
779
				array('id' => $id)
780
			);
781
		}
782
783
		if ($noCollection) {
784
			$me = $this->getContact(null, $id, $options);
785
			$addressBookId = $me['parent'];
786
		}
787
788
		try {
789
790
			$result = $this->getPreparedQuery('deletecontact')
791
				->execute(array($id, $addressBookId));
792
793 View Code Duplication
			if (\OCP\DB::isError($result)) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
794
				\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: '
795
					. \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
796
				return false;
797
			}
798
799
		} catch(\Exception $e) {
800
			\OCP\Util::writeLog('contacts', __METHOD__.
801
				', exception: ' . $e->getMessage(), \OCP\Util::ERROR);
802
			\OCP\Util::writeLog('contacts', __METHOD__.', id: '
803
				. $id, \OCP\Util::DEBUG);
804
			return false;
805
		}
806
807
		$this->setModifiedAddressBook($addressBookId);
808
		return true;
809
	}
810
811
	/**
812
	 * @brief Get the last modification time for a contact.
813
	 *
814
	 * Must return a UNIX time stamp or null if the backend
815
	 * doesn't support it.
816
	 *
817
	 * @param string $addressBookId
818
	 * @param mixed $id
819
	 * @returns int | null
820
	 */
821
	public function lastModifiedContact($addressBookId, $id) {
822
823
		$contact = $this->getContact($addressBookId, $id);
824
		return ($contact ? $contact['lastmodified'] : null);
825
826
	}
827
828
	/**
829
	 * @brief Get the contact id from the uri.
830
	 *
831
	 * @param string $addressBookId
832
	 * @returns int | null
833
	 */
834
	public function getIdFromUri($addressBookId,$uri) {
835
836
		$stmt = $this->getPreparedQuery('contactidfromuri');
837
		$result = $stmt->execute(array($addressBookId,$uri));
838
839 View Code Duplication
		if (\OCP\DB::isError($result)) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
840
			\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
841
			return null;
842
		}
843
844
		$one = $result->fetchOne();
845
846 View Code Duplication
		if (!$one) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
847
			\OCP\Util::writeLog('contacts', __METHOD__.', Not found, uri: '. $uri, \OCP\Util::DEBUG);
848
			return null;
849
		}
850
851
		return $one;
852
	}
853
854
	/**
855
	 * Create a unique URI based on the display name.
856
	 *
857
	 * @param string $displayName
858
	 * @return string
859
	 */
860 2
	private function createAddressBookURI($displayName) {
861
862 2
		$name = str_replace(' ', '_', strtolower($displayName));
863
864
		try {
865 2
			$stmt = $this->getPreparedQuery('addressbookuris');
866 2
			$result = $stmt->execute(array($this->userid));
867
868 2 View Code Duplication
			if (\OCP\DB::isError($result)) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
869
				\OCP\Util::writeLog('contacts',
870
					__METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result),
871
					\OCP\Util::ERROR
872
				);
873
				return $name;
874
			}
875
876 2
		} catch(\Exception $e) {
877
			\OCP\Util::writeLog('contacts', __METHOD__ . ' exception: ' . $e->getMessage(), \OCP\Util::ERROR);
878
			return $name;
879
		}
880 2
		$uris = array();
881 2
		while ($row = $result->fetchRow()) {
882
			$uris[] = $row['uri'];
883
		}
884
885 2
		$newname = $name;
886
		$i = 1
887 2
		;
888 2
		while (in_array($newname, $uris)) {
889
			$newname = $name.$i;
890
			$i = $i + 1;
891
		}
892 2
		return $newname;
893
	}
894
895
	/**
896
	* @brief Checks if a contact with the same URI already exist in the address book.
897
	* @param string $addressBookId Address book ID.
898
	* @param string $uri
899
	* @returns string Unique URI
900
	*/
901 2
	protected function uniqueURI($addressBookId, $uri) {
902 2
		$stmt = $this->getPreparedQuery('counturi');
903
904 2
		$result = $stmt->execute(array($addressBookId, $uri));
905 2
		$result = $result->fetchRow();
906
907 2
		if (is_array($result) && count($result) > 0 && $result['count'] > 0) {
908
909
			while (true) {
910
				$uri = Properties::generateUID() . '.vcf';
911
				$result = $stmt->execute(array($addressBookId, $uri));
912
913
				if (is_array($result) && count($result) > 0 && $result['count'] > 0) {
914
					continue;
915
				} else {
916
					return $uri;
917
				}
918
919
			}
920
		}
921
922 2
		return $uri;
923
	}
924
925
	/**
926
	* Collect (nearly) all queries in one place
927
	*
928
	* @param string $identifier
929
	* @param array $options Can be used for e.g. offset/limit
930
	* @throws \Exception If $identifier isn't known
931
	* @return \OC_DB_StatementWrapper
932
	*/
933 2
	protected function getPreparedQuery($identifier, array $options = array()) {
934
935 2
		if (isset(self::$preparedQueries[$identifier])) {
936 2
			return self::$preparedQueries[$identifier];
937
		}
938
939 1
		$args = array();
940
941
		switch ($identifier) {
942
943 1
			case 'getaddressbooksforuser':
944
				$args[] = 'SELECT `id`, `displayname`, `description`, `ctag`'
945
					. ' AS `lastmodified`, `userid` AS `owner`, `uri` FROM `'
946
					. $this->addressBooksTableName
947
					. '` WHERE `userid` = ? ORDER BY `displayname`';
948
				break;
949 1
			case 'getaddressbook':
950 1
				$args[] = 'SELECT `id`, `displayname`, `description`, '
951
						. '`userid` AS `owner`, `ctag` AS `lastmodified`, `uri` FROM `'
952 1
						. $this->addressBooksTableName
953 1
						. '` WHERE `id` = ? AND `userid` = ?';
954 1
				break;
955 1
			case 'createaddressbook':
956 1
				$args[] = 'INSERT INTO `'
957 1
						. $this->addressBooksTableName . '` '
958 1
						. '(`userid`,`displayname`,`uri`,`description`,`ctag`) '
959 1
						. 'VALUES(?,?,?,?,?)';
960 1
				break;
961 1
			case 'deleteaddressbookcontacts':
962
				$args[] = 'DELETE FROM `' . $this->cardsTableName
963
						. '` WHERE `addressbookid` = ?';
964
				break;
965 1
			case 'deleteaddressbook':
966
				$args[] = 'DELETE FROM `'
967
						. $this->addressBooksTableName . '` WHERE `id` = ?';
968
				break;
969 1
			case 'touchaddressbook':
970 1
				$args[] = 'UPDATE `' . $this->addressBooksTableName
971 1
						. '` SET `ctag` = ? + 1 WHERE `id` = ?';
972 1
				break;
973 1
			case 'counturi':
974 1
				$args[] = 'SELECT COUNT(*) AS `count` FROM `'
975 1
						. $this->cardsTableName
976 1
						. '` WHERE `addressbookid` = ? AND `uri` = ?';
977 1
				break;
978 1
			case 'addressbookuris':
979 1
				$args[] = 'SELECT `uri` FROM `'
980 1
						. $this->addressBooksTableName . '` WHERE `userid` = ? ';
981 1
				break;
982 1
			case 'contactidfromuri':
983
				$args[] = 'SELECT `id` FROM `'
984
						. $this->cardsTableName
985
						. '` WHERE `addressbookid` = ? AND `uri` = ? ';
986
				break;
987 1
			case 'deletecontact':
988
				$args[] = 'DELETE FROM `'
989
					. $this->cardsTableName
990
					. '` WHERE `id` = ? AND `addressbookid` = ?';
991
				break;
992 1
			case 'updatecontact':
993
				$args[] = 'UPDATE `' . $this->cardsTableName
994
						. '` SET `fullname` = ?,`carddata` = ?, `lastmodified` = ?'
995
						. ' WHERE `id` = ? AND `addressbookid` = ?';
996
				break;
997 1
			case 'createcontact':
998 1
				$args[] = 'INSERT INTO `'
999 1
					. $this->cardsTableName
1000 1
					. '` (`addressbookid`,`fullname`,`carddata`,`uri`,`lastmodified`) '
1001 1
					. ' VALUES(?,?,?,?,?)';
1002 1
				break;
1003 1
			case 'getcontactbyid':
1004 1
				$args[] = 'SELECT `id`, `uri`, `carddata`, `lastmodified`, '
1005
						. '`addressbookid` AS `parent`, `fullname` AS `displayname` FROM `'
1006 1
						. $this->cardsTableName
1007 1
						. '` WHERE `id` = ? AND `addressbookid` = ?';
1008 1
				break;
1009
			case 'getcontactbyuri':
1010
				$args[] = 'SELECT `id`, `uri`, `carddata`, `lastmodified`, '
1011
						. '`addressbookid` AS `parent`, `fullname` AS `displayname` FROM `'
1012
						. $this->cardsTableName
1013
						. '` WHERE `uri` = ? AND `addressbookid` = ?';
1014
				break;
1015
			case 'getcontactbyidnocollection':
1016
				$args[] = 'SELECT `id`, `uri`, `carddata`, `lastmodified`, '
1017
						. '`addressbookid` AS `parent`, `fullname` AS `displayname` FROM `'
1018
						. $this->cardsTableName . '` WHERE `id` = ?';
1019
				break;
1020
			case 'getcontactbyurinocollection':
1021
				$args[] = 'SELECT `id`, `uri`, `carddata`, `lastmodified`, '
1022
						. '`addressbookid` AS `parent`, `fullname` AS `displayname` FROM `'
1023
						. $this->cardsTableName . '` WHERE `uri` = ?';
1024
				break;
1025
			case 'getcontactids':
1026
				$args[] = 'SELECT `id` FROM `'
1027
						. $this->cardsTableName . '` WHERE `addressbookid` = ?';
1028
				break;
1029 View Code Duplication
			case 'getcontacts':
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1030
				$args[] = 'SELECT `id`, `uri`, `carddata`, `lastmodified`, '
1031
						. '`addressbookid` AS `parent`, `fullname` AS `displayname` FROM `'
1032
						. $this->cardsTableName . '` WHERE `addressbookid` = ?';
1033
				$args[] = isset($options['limit']) ? $options['limit'] : null;
1034
				$args[] = isset($options['offset']) ? $options['offset'] : null;
1035
				break;
1036 View Code Duplication
			case 'getcontactsomitdata':
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1037
				$args[] = 'SELECT `id`, `uri`, `lastmodified`, '
1038
						. '`addressbookid` AS `parent`, `fullname` AS `displayname` FROM `'
1039
						. $this->cardsTableName . '` WHERE `addressbookid` = ?';
1040
				$args[] = isset($options['limit']) ? $options['limit'] : null;
1041
				$args[] = isset($options['offset']) ? $options['offset'] : null;
1042
				break;
1043
			case 'numcontacts':
1044
				$args[] = 'SELECT COUNT(*) AS `count` FROM `'
1045
						. $this->cardsTableName . '` WHERE `addressbookid` = ?';
1046
				break;
1047
			default:
1048
				throw new \Exception('Unknown query identifier: ' . $identifier);
1049
1050
		}
1051
1052 1
		self::$preparedQueries[$identifier] = call_user_func_array('\OCP\DB::prepare', $args);
1053
1054 1
		return self::$preparedQueries[$identifier];
1055
	}
1056
1057
	public function getSearchProvider($addressbook) {
1058
		return new \OCA\Contacts\AddressbookProvider($addressbook);
1059
	}
1060
1061
}
1062