pkgfuncs.inc.php 25.3 KB
Newer Older
1
<?php
2

3
include_once("pkgbasefuncs.inc.php");
eric's avatar
eric committed
4

5
6
7
8
9
10
11
12
13
14
/**
 * Determine if the user can delete a specific package comment
 *
 * Only the comment submitter, Trusted Users, and Developers can delete
 * comments. This function is used for the backend side of comment deletion.
 *
 * @param string $comment_id The comment ID in the database
 *
 * @return bool True if the user can delete the comment, otherwise false
 */
Lukas Fleischer's avatar
Lukas Fleischer committed
15
function can_delete_comment($comment_id=0) {
16
	$dbh = DB::connect();
Lukas Fleischer's avatar
Lukas Fleischer committed
17

18
19
	$q = "SELECT UsersID FROM PackageComments ";
	$q.= "WHERE ID = " . intval($comment_id);
canyonknight's avatar
canyonknight committed
20
	$result = $dbh->query($q);
Lukas Fleischer's avatar
Lukas Fleischer committed
21
22
23

	if (!$result) {
		return false;
24
	}
Lukas Fleischer's avatar
Lukas Fleischer committed
25

26
27
28
	$uid = $result->fetch(PDO::FETCH_COLUMN, 0);

	return has_credential(CRED_COMMENT_DELETE, array($uid));
29
}
eric's avatar
eric committed
30

31
32
33
34
35
36
37
38
39
40
/**
 * Determine if the user can delete a specific package comment using an array
 *
 * Only the comment submitter, Trusted Users, and Developers can delete
 * comments. This function is used for the frontend side of comment deletion.
 *
 * @param array $comment All database information relating a specific comment
 *
 * @return bool True if the user can delete the comment, otherwise false
 */
Lukas Fleischer's avatar
Lukas Fleischer committed
41
42
function can_delete_comment_array($comment) {
	return has_credential(CRED_COMMENT_DELETE, array($comment['UsersID']));
43
44
}

45
46
47
48
49
50
51
/**
 * Check to see if the package name already exists in the database
 *
 * @param string $name The package name to check
 *
 * @return string|void Package name if it already exists
 */
52
function pkg_from_name($name="") {
53
	if (!$name) {return NULL;}
54
	$dbh = DB::connect();
55
	$q = "SELECT ID FROM Packages ";
canyonknight's avatar
canyonknight committed
56
57
58
59
60
61
	$q.= "WHERE Name = " . $dbh->quote($name);
	$result = $dbh->query($q);
	if (!$result) {
		return;
	}
	$row = $result->fetch(PDO::FETCH_NUM);
62
63
64
	return $row[0];
}

65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
/**
 * Get licenses for a specific package
 *
 * @param int $pkgid The package to get licenses for
 *
 * @return array All licenses for the package
 */
function pkg_licenses($pkgid) {
	$lics = array();
	$pkgid = intval($pkgid);
	if ($pkgid > 0) {
		$dbh = DB::connect();
		$q = "SELECT l.Name FROM Licenses l ";
		$q.= "INNER JOIN PackageLicenses pl ON pl.LicenseID = l.ID ";
		$q.= "WHERE pl.PackageID = ". $pkgid;
		$result = $dbh->query($q);
		if (!$result) {
			return array();
		}
		while ($row = $result->fetch(PDO::FETCH_COLUMN, 0)) {
			$lics[] = $row;
		}
	}
	return $lics;
}

91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/**
 * Get package groups for a specific package
 *
 * @param int $pkgid The package to get groups for
 *
 * @return array All package groups for the package
 */
function pkg_groups($pkgid) {
	$grps = array();
	$pkgid = intval($pkgid);
	if ($pkgid > 0) {
		$dbh = DB::connect();
		$q = "SELECT g.Name FROM Groups g ";
		$q.= "INNER JOIN PackageGroups pg ON pg.GroupID = g.ID ";
		$q.= "WHERE pg.PackageID = ". $pkgid;
		$result = $dbh->query($q);
		if (!$result) {
			return array();
		}
		while ($row = $result->fetch(PDO::FETCH_COLUMN, 0)) {
			$grps[] = $row;
		}
	}
	return $grps;
}

117
118
119
120
121
122
123
/**
 * Get package dependencies for a specific package
 *
 * @param int $pkgid The package to get dependencies for
 *
 * @return array All package dependencies for the package
 */
124
function pkg_dependencies($pkgid) {
125
	$deps = array();
126
127
	$pkgid = intval($pkgid);
	if ($pkgid > 0) {
128
		$dbh = DB::connect();
129
		$q = "SELECT pd.DepName, dt.Name, pd.DepCondition, pd.DepArch, p.ID FROM PackageDepends pd ";
Dan McGee's avatar
Dan McGee committed
130
		$q.= "LEFT JOIN Packages p ON pd.DepName = p.Name ";
131
		$q.= "OR SUBSTRING(pd.DepName FROM 1 FOR POSITION(': ' IN pd.DepName) - 1) = p.Name ";
132
		$q.= "LEFT JOIN DependencyTypes dt ON dt.ID = pd.DepTypeID ";
Dan McGee's avatar
Dan McGee committed
133
134
		$q.= "WHERE pd.PackageID = ". $pkgid . " ";
		$q.= "ORDER BY pd.DepName";
canyonknight's avatar
canyonknight committed
135
136
137
138
139
		$result = $dbh->query($q);
		if (!$result) {
			return array();
		}
		while ($row = $result->fetch(PDO::FETCH_NUM)) {
140
141
142
143
144
145
			$deps[] = $row;
		}
	}
	return $deps;
}

146
147
148
149
150
151
152
153
154
155
156
157
/**
 * Get package relations for a specific package
 *
 * @param int $pkgid The package to get relations for
 *
 * @return array All package relations for the package
 */
function pkg_relations($pkgid) {
	$rels = array();
	$pkgid = intval($pkgid);
	if ($pkgid > 0) {
		$dbh = DB::connect();
158
		$q = "SELECT pr.RelName, rt.Name, pr.RelCondition, pr.RelArch, p.ID FROM PackageRelations pr ";
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
		$q.= "LEFT JOIN Packages p ON pr.RelName = p.Name ";
		$q.= "LEFT JOIN RelationTypes rt ON rt.ID = pr.RelTypeID ";
		$q.= "WHERE pr.PackageID = ". $pkgid . " ";
		$q.= "ORDER BY pr.RelName";
		$result = $dbh->query($q);
		if (!$result) {
			return array();
		}
		while ($row = $result->fetch(PDO::FETCH_NUM)) {
			$rels[] = $row;
		}
	}
	return $rels;
}

174
175
176
177
178
179
/**
 * Get the HTML code to display a package dependency link
 *
 * @param string $name The name of the dependency
 * @param string $type The name of the dependency type
 * @param string $cond The package dependency condition string
180
 * @param string $arch The package dependency architecture
181
 * @param int $pkg_id The package of the package to display the dependency for
182
 * @param bool $show_desc Whether the description of optdepends is shown
183
184
185
 *
 * @return string The HTML code of the label to display
 */
186
function pkg_depend_link($name, $type, $cond, $arch, $pkg_id, $show_desc=true) {
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
	if ($type == 'optdepends' && strpos($name, ':') !== false) {
		$tokens = explode(':', $name, 2);
		$name = $tokens[0];
		$desc = $tokens[1];
	} else {
		$desc = '(unknown)';
	}

	$link = '<a href="';
	if (is_null($pkg_id)) {
		$link .= 'https://www.archlinux.org/packages/?q=' . urlencode($name);
	} else {
		$link .= htmlspecialchars(get_pkg_uri($name), ENT_QUOTES);
	}
	$link .= '" title="' . __('View packages details for') .' ' . htmlspecialchars($name) . '">';
	$link .= htmlspecialchars($name) . '</a>';
	$link .= htmlspecialchars($cond);

205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
	if ($type != 'depends' || $arch) {
		$link .= ' <em>(';

		if ($type == 'makedepends') {
			$link .= 'make';
		} elseif ($type == 'checkdepends') {
			$link .= 'check';
		} elseif ($type == 'optdepends') {
			$link .= 'optional';
		}

		if ($type != 'depends' && $arch) {
			$link .= ', ';
		}

		if ($arch) {
			$link .= htmlspecialchars($arch);
		}

		$link .= ')';
225
		if ($show_desc && $type == 'optdepends') {
226
227
228
			$link .= ' &ndash; ' . htmlspecialchars($desc) . ' </em>';
		}
		$link .= '</em>';
229
230
231
232
	}

	return $link;
}
233

234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
/**
 * Get the HTML code to display a package relation
 *
 * @param string $name The name of the relation
 * @param string $cond The package relation condition string
 * @param string $arch The package relation architecture
 *
 * @return string The HTML code of the label to display
 */
function pkg_rel_html($name, $cond, $arch) {
	$html = htmlspecialchars($name) . htmlspecialchars($cond);

	if ($arch) {
		$html .= ' <em>(' . htmlspecialchars($arch) . ')</em>';
	}

	return $html;
}

253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
/**
 * Get the HTML code to display a source link
 *
 * @param string $url The URL of the source
 * @param string $arch The source architecture
 *
 * @return string The HTML code of the label to display
 */
function pkg_source_link($url, $arch) {
	$url = explode('::', $url);
	$parsed_url = parse_url($url[0]);

	if (isset($parsed_url['scheme']) || isset($url[1])) {
		$link = '<a href="' .  htmlspecialchars((isset($url[1]) ? $url[1] : $url[0]), ENT_QUOTES) . '">' . htmlspecialchars($url[0]) . '</a>';
	} else {
		$link = htmlspecialchars($url[0]);
	}

	if ($arch) {
		$link .= ' <em>(' . htmlspecialchars($arch) . ')</em>';
	}

	return $link;
}

278
279
280
281
282
283
284
/**
 * Determine packages that depend on a package
 *
 * @param string $name The package name for the dependency search
 *
 * @return array All packages that depend on the specified package name
 */
285
function pkg_required($name="") {
286
	$deps = array();
Dan McGee's avatar
Dan McGee committed
287
	if ($name != "") {
288
		$dbh = DB::connect();
289
290
291
292
293
		$q = "SELECT p.Name, dt.Name, '' AS DepCondition, pd.DepArch, p.ID FROM PackageDepends pd ";
		$q.= "LEFT JOIN Packages p ON p.ID = pd.PackageID ";
		$q.= "LEFT JOIN DependencyTypes dt ON dt.ID = pd.DepTypeID ";
		$q.= "WHERE pd.DepName = " . $dbh->quote($name) . " ";
		$q.= "OR SUBSTRING(pd.DepName FROM 1 FOR POSITION(': ' IN pd.DepName) - 1) = " . $dbh->quote($name) . " ";
Dan McGee's avatar
Dan McGee committed
294
		$q.= "ORDER BY p.Name";
canyonknight's avatar
canyonknight committed
295
		$result = $dbh->query($q);
296
		if (!$result) {return array();}
canyonknight's avatar
canyonknight committed
297
		while ($row = $result->fetch(PDO::FETCH_NUM)) {
298
299
300
301
302
303
			$deps[] = $row;
		}
	}
	return $deps;
}

304
305
306
307
308
309
310
/**
 * Get all package sources for a specific package
 *
 * @param string $pkgid The package ID to get the sources for
 *
 * @return array All sources associated with a specific package
 */
311
function pkg_sources($pkgid) {
312
	$sources = array();
313
314
	$pkgid = intval($pkgid);
	if ($pkgid > 0) {
315
		$dbh = DB::connect();
316
		$q = "SELECT Source, SourceArch FROM PackageSources ";
317
		$q.= "WHERE PackageID = " . $pkgid;
318
		$q.= " ORDER BY Source";
canyonknight's avatar
canyonknight committed
319
320
321
322
323
		$result = $dbh->query($q);
		if (!$result) {
			return array();
		}
		while ($row = $result->fetch(PDO::FETCH_NUM)) {
324
			$sources[] = $row;
325
326
327
328
329
		}
	}
	return $sources;
}

330
331
332
333
334
335
336
/**
 * Determine package names from package IDs
 *
 * @param string|array $pkgids The package IDs to get names for
 *
 * @return array|string All names if multiple package IDs, otherwise package name
 */
337
function pkg_name_from_id($pkgids) {
338
339
340
	if (is_array($pkgids)) {
		$pkgids = sanitize_ids($pkgids);
		$names = array();
341
		$dbh = DB::connect();
canyonknight's avatar
canyonknight committed
342
343
344
345
346
		$q = "SELECT Name FROM Packages WHERE ID IN (";
		$q.= implode(",", $pkgids) . ")";
		$result = $dbh->query($q);
		if ($result) {
			while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
347
348
349
350
351
352
				$names[] = $row['Name'];
			}
		}
		return $names;
	}
	elseif ($pkgids > 0) {
353
		$dbh = DB::connect();
354
		$q = "SELECT Name FROM Packages WHERE ID = " . $pkgids;
canyonknight's avatar
canyonknight committed
355
356
357
		$result = $dbh->query($q);
		if ($result) {
			$name = $result->fetch(PDO::FETCH_NUM);
358
		}
canyonknight's avatar
canyonknight committed
359
		return $name[0];
360
361
362
	}
	else {
		return NULL;
363
364
365
	}
}

366
367
368
369
370
371
372
/**
 * Determine if a package name is on the database blacklist
 *
 * @param string $name The package name to check
 *
 * @return bool True if the name is blacklisted, otherwise false
 */
373
function pkg_name_is_blacklisted($name) {
374
	$dbh = DB::connect();
canyonknight's avatar
canyonknight committed
375
376
377
	$q = "SELECT COUNT(*) FROM PackageBlacklist ";
	$q.= "WHERE Name = " . $dbh->quote($name);
	$result = $dbh->query($q);
378
379

	if (!$result) return false;
380
	return ($result->fetchColumn() > 0);
381
382
}

383
/**
384
 * Get the package details
385
 *
386
 * @param string $id The package ID to get description for
387
 *
388
389
 * @return array The package's details OR error message
 **/
390
function pkg_get_details($id=0) {
391
	$dbh = DB::connect();
392

393
	$q = "SELECT Packages.*, PackageBases.ID AS BaseID, ";
394
	$q.= "PackageBases.Name AS BaseName, ";
395
396
397
	$q.= "PackageBases.NumVotes, PackageBases.OutOfDateTS, ";
	$q.= "PackageBases.SubmittedTS, PackageBases.ModifiedTS, ";
	$q.= "PackageBases.SubmitterUID, PackageBases.MaintainerUID, ";
398
	$q.= "PackageBases.PackagerUID, ";
399
400
401
	$q.= "(SELECT COUNT(*) FROM PackageRequests ";
	$q.= " WHERE PackageRequests.PackageBaseID = Packages.PackageBaseID ";
	$q.= " AND PackageRequests.Status = 0) AS RequestCount ";
402
	$q.= "FROM Packages, PackageBases ";
403
	$q.= "WHERE PackageBases.ID = Packages.PackageBaseID ";
Loui Chang's avatar
Loui Chang committed
404
	$q.= "AND Packages.ID = " . intval($id);
canyonknight's avatar
canyonknight committed
405
	$result = $dbh->query($q);
eric's avatar
eric committed
406

407
408
	$row = array();

canyonknight's avatar
canyonknight committed
409
	if (!$result) {
410
		$row['error'] = __("Error retrieving package details.");
411
412
	}
	else {
canyonknight's avatar
canyonknight committed
413
		$row = $result->fetch(PDO::FETCH_ASSOC);
eric's avatar
eric committed
414
		if (empty($row)) {
415
			$row['error'] = __("Package details could not be found.");
416
		}
417
418
419
420
421
422
423
424
425
	}

	return $row;
}

/**
 * Display the package details page
 *
 * @param string $id The package ID to get details page for
426
 * @param array $row Package details retrieved by pkg_get_details()
427
428
429
430
 * @param string $SID The session ID of the visitor
 *
 * @return void
 */
431
function pkg_display_details($id=0, $row, $SID="") {
432
	$dbh = DB::connect();
433

434
435
436
437
	if (isset($row['error'])) {
		print "<p>" . $row['error'] . "</p>\n";
	}
	else {
438
439
440
		$base_id = pkgbase_from_pkgid($id);
		$pkgbase_name = pkgbase_name_from_id($base_id);

441
442
443
444
445
446
		include('pkg_details.php');

		if ($SID) {
			include('pkg_comment_form.php');
		}

Lukas Fleischer's avatar
Lukas Fleischer committed
447
		$limit = isset($_GET['comments']) ? 0 : 10;
448
449
		$include_deleted = has_credential(CRED_COMMENT_VIEW_DELETED);
		$comments = pkgbase_comments($base_id, $limit, $include_deleted);
450
451
		if (!empty($comments)) {
			include('pkg_comments.php');
eric's avatar
eric committed
452
453
454
455
		}
	}
}

Simo Leone's avatar
Simo Leone committed
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
/* pkg_search_page(SID)
 * outputs the body of search/search results page
 *
 * parameters:
 *  SID - current Session ID
 * preconditions:
 *  package search page has been accessed
 *  request variables have not been sanitized
 *
 *  request vars:
 *    O  - starting result number
 *    PP - number of search hits per page
 *    K  - package search string
 *    SO - search hit sort order:
 *          values: a - ascending
 *                  d - descending
 *    SB - sort search hits by:
473
 *          values: n - package name
Simo Leone's avatar
Simo Leone committed
474
475
476
 *                  v - number of votes
 *                  m - maintainer username
 *    SeB- property that search string (K) represents
Andrea Scarpino's avatar
Andrea Scarpino committed
477
478
 *          values: n  - package name
 *                  nd - package name & description
479
 *                  x  - package name (exact match)
Simo Leone's avatar
Simo Leone committed
480
481
482
483
484
485
486
487
488
489
490
491
492
493
 *                  m  - package maintainer's username
 *                  s  - package submitter's username
 *    do_Orphans    - boolean. whether to search packages
 *                     without a maintainer
 *
 *
 *    These two are actually handled in packages.php.
 *
 *    IDs- integer array of ticked packages' IDs
 *    action - action to be taken on ticked packages
 *             values: do_Flag   - Flag out-of-date
 *                     do_UnFlag - Remove out-of-date flag
 *                     do_Adopt  - Adopt
 *                     do_Disown - Disown
494
 *                     do_Delete - Delete
495
496
 *                     do_Notify - Enable notification
 *                     do_UnNotify - Disable notification
Simo Leone's avatar
Simo Leone committed
497
 */
498
function pkg_search_page($SID="") {
499
	$dbh = DB::connect();
Loui Chang's avatar
Loui Chang committed
500

501
502
503
504
	/*
	 * Get commonly used variables.
	 * TODO: Reduce the number of database queries!
	 */
Loui Chang's avatar
Loui Chang committed
505
	if ($SID)
506
		$myuid = uid_from_sid($SID);
Loui Chang's avatar
Loui Chang committed
507

508
	/* Sanitize paging variables. */
Loui Chang's avatar
Loui Chang committed
509
	if (isset($_GET['O'])) {
510
511
		$_GET['O'] = max(intval($_GET['O']), 0);
	} else {
Loui Chang's avatar
Loui Chang committed
512
513
514
515
		$_GET['O'] = 0;
	}

	if (isset($_GET["PP"])) {
516
517
		$_GET["PP"] = bound(intval($_GET["PP"]), 50, 250);
	} else {
518
		$_GET["PP"] = 50;
Loui Chang's avatar
Loui Chang committed
519
520
	}

521
522
523
524
	/*
	 * FIXME: Pull out DB-related code. All of it! This one's worth a
	 * choco-chip cookie, one of those nice big soft ones.
	 */
Loui Chang's avatar
Loui Chang committed
525

526
	/* Build the package search query. */
527
	$q_select = "SELECT ";
Loui Chang's avatar
Loui Chang committed
528
	if ($SID) {
529
		$q_select .= "CommentNotify.UserID AS Notify,
530
			   PackageVotes.UsersID AS Voted, ";
Loui Chang's avatar
Loui Chang committed
531
	}
532
	$q_select .= "Users.Username AS Maintainer,
533
	Packages.Name, Packages.Version, Packages.Description,
534
535
	PackageBases.NumVotes, PackageBases.Popularity, Packages.ID,
	Packages.PackageBaseID, PackageBases.OutOfDateTS ";
Loui Chang's avatar
Loui Chang committed
536

537
	$q_from = "FROM Packages
538
	LEFT JOIN PackageBases ON (PackageBases.ID = Packages.PackageBaseID)
539
	LEFT JOIN Users ON (PackageBases.MaintainerUID = Users.ID) ";
Loui Chang's avatar
Loui Chang committed
540
	if ($SID) {
541
		/* This is not needed for the total row count query. */
542
		$q_from_extra = "LEFT JOIN PackageVotes
543
		ON (PackageBases.ID = PackageVotes.PackageBaseID AND PackageVotes.UsersID = $myuid)
Loui Chang's avatar
Loui Chang committed
544
		LEFT JOIN CommentNotify
545
		ON (PackageBases.ID = CommentNotify.PackageBaseID AND CommentNotify.UserID = $myuid) ";
546
547
	} else {
		$q_from_extra = "";
Loui Chang's avatar
Loui Chang committed
548
549
	}

550
	$q_where = 'WHERE PackageBases.PackagerUID IS NOT NULL ';
Loui Chang's avatar
Loui Chang committed
551

552
553
	if (isset($_GET['K'])) {
		if (isset($_GET["SeB"]) && $_GET["SeB"] == "m") {
554
			/* Search by maintainer. */
canyonknight's avatar
canyonknight committed
555
			$q_where .= "AND Users.Username = " . $dbh->quote($_GET['K']) . " ";
Loui Chang's avatar
Loui Chang committed
556
		}
557
		elseif (isset($_GET["SeB"]) && $_GET["SeB"] == "s") {
558
			/* Search by submitter. */
559
			$q_where .= "AND SubmitterUID = " . intval(uid_from_username($_GET['K'])) . " ";
Loui Chang's avatar
Loui Chang committed
560
		}
561
		elseif (isset($_GET["SeB"]) && $_GET["SeB"] == "n") {
562
			/* Search by name. */
canyonknight's avatar
canyonknight committed
563
			$K = "%" . addcslashes($_GET['K'], '%_') . "%";
564
			$q_where .= "AND (Packages.Name LIKE " . $dbh->quote($K) . ") ";
Andrea Scarpino's avatar
Andrea Scarpino committed
565
		}
566
567
568
569
570
571
		elseif (isset($_GET["SeB"]) && $_GET["SeB"] == "b") {
			/* Search by package base name. */
			$K = "%" . addcslashes($_GET['K'], '%_') . "%";
			$q_where .= "AND (PackageBases.Name LIKE " . $dbh->quote($K) . ") ";
		}
		elseif (isset($_GET["SeB"]) && $_GET["SeB"] == "N") {
572
			/* Search by name (exact match). */
573
			$q_where .= "AND (Packages.Name = " . $dbh->quote($_GET['K']) . ") ";
574
		}
575
576
577
578
		elseif (isset($_GET["SeB"]) && $_GET["SeB"] == "B") {
			/* Search by package base name (exact match). */
			$q_where .= "AND (PackageBases.Name = " . $dbh->quote($_GET['K']) . ") ";
		}
Loui Chang's avatar
Loui Chang committed
579
		else {
580
			/* Keyword search (default). */
581
			$count = 0;
582
			$q_keywords = "";
583
			$op = "";
584

585
			foreach (str_getcsv($_GET['K'], ' ') as $term) {
586
587
588
				if ($term == "") {
					continue;
				}
589
590
591
592
593
594
595
596
597
598
599
600
				if ($count > 0 && strtolower($term) == "and") {
					$op = "AND ";
					continue;
				}
				if ($count > 0 && strtolower($term) == "or") {
					$op = "OR ";
					continue;
				}
			        if ($count > 0 && strtolower($term) == "not") {
					$op .= "NOT ";
					continue;
				}
601

602
				$term = "%" . addcslashes($term, '%_') . "%";
603
				$q_keywords .= $op . " (Packages.Name LIKE " . $dbh->quote($term) . " OR ";
604
605
606
607
				$q_keywords .= "Description LIKE " . $dbh->quote($term) . " OR ";
				$q_keywords .= "EXISTS (SELECT * FROM PackageKeywords WHERE ";
				$q_keywords .= "PackageKeywords.PackageBaseID = Packages.PackageBaseID AND ";
				$q_keywords .= "PackageKeywords.Keyword LIKE " . $dbh->quote($term) . ")) ";
608
609
610
611
612

				$count++;
				if ($count >= 20) {
					break;
				}
613
				$op = "AND ";
614
			}
615

616
617
618
			if (!empty($q_keywords)) {
				$q_where .= "AND (" . $q_keywords . ") ";
			}
Loui Chang's avatar
Loui Chang committed
619
620
621
		}
	}

622
	if (isset($_GET["do_Orphans"])) {
623
		$q_where .= "AND MaintainerUID IS NULL ";
Loui Chang's avatar
Loui Chang committed
624
	}
625

626
	if (isset($_GET['outdated'])) {
627
		if ($_GET['outdated'] == 'on') {
628
			$q_where .= "AND OutOfDateTS IS NOT NULL ";
629
630
		}
		elseif ($_GET['outdated'] == 'off') {
631
			$q_where .= "AND OutOfDateTS IS NULL ";
632
		}
633
634
	}

635
	$order = (isset($_GET["SO"]) && $_GET["SO"] == 'd') ? 'DESC' : 'ASC';
Loui Chang's avatar
Loui Chang committed
636

637
	$q_sort = "ORDER BY ";
638
639
	$sort_by = isset($_GET["SB"]) ? $_GET["SB"] : '';
	switch ($sort_by) {
Loui Chang's avatar
Loui Chang committed
640
	case 'v':
641
		$q_sort .= "NumVotes " . $order . ", ";
Loui Chang's avatar
Loui Chang committed
642
		break;
643
644
645
	case 'p':
		$q_sort .= "Popularity " . $order . ", ";
		break;
646
647
	case 'w':
		if ($SID) {
648
			$q_sort .= "Voted " . $order . ", ";
649
650
651
652
		}
		break;
	case 'o':
		if ($SID) {
653
			$q_sort .= "Notify " . $order . ", ";
654
655
		}
		break;
Loui Chang's avatar
Loui Chang committed
656
	case 'm':
657
		$q_sort .= "Maintainer " . $order . ", ";
Loui Chang's avatar
Loui Chang committed
658
659
		break;
	case 'a':
660
		$q_sort .= "-ModifiedTS " . $order . ", ";
Loui Chang's avatar
Loui Chang committed
661
662
663
664
		break;
	default:
		break;
	}
665
	$q_sort .= " Packages.Name " . $order . " ";
Loui Chang's avatar
Loui Chang committed
666

667
	$q_limit = "LIMIT ".$_GET["PP"]." OFFSET ".$_GET["O"];
668

669
670
	$q = $q_select . $q_from . $q_from_extra . $q_where . $q_sort . $q_limit;
	$q_total = "SELECT COUNT(*) " . $q_from . $q_where;
Loui Chang's avatar
Loui Chang committed
671

canyonknight's avatar
canyonknight committed
672
673
	$result = $dbh->query($q);
	$result_t = $dbh->query($q_total);
674
	if ($result_t) {
canyonknight's avatar
canyonknight committed
675
676
		$row = $result_t->fetch(PDO::FETCH_NUM);
		$total = $row[0];
677
678
679
680
	}
	else {
		$total = 0;
	}
Simo Leone's avatar
Simo Leone committed
681

682
	if ($result && $total > 0) {
683
684
		if (isset($_GET["SO"]) && $_GET["SO"] == "d"){
			$SO_next = "a";
Loui Chang's avatar
Loui Chang committed
685
686
		}
		else {
687
			$SO_next = "d";
Loui Chang's avatar
Loui Chang committed
688
		}
689
	}
Simo Leone's avatar
Simo Leone committed
690

691
	/* Calculate the results to use. */
Loui Chang's avatar
Loui Chang committed
692
	$first = $_GET['O'] + 1;
Simo Leone's avatar
Simo Leone committed
693

694
	/* Calculation of pagination links. */
695
696
697
698
	$per_page = ($_GET['PP'] > 0) ? $_GET['PP'] : 50;
	$current = ceil($first / $per_page);
	$pages = ceil($total / $per_page);
	$templ_pages = array();
699

700
	if ($current > 1) {
701
702
		$templ_pages['&laquo; ' . __('First')] = 0;
		$templ_pages['&lsaquo; ' . __('Previous')] = ($current - 2) * $per_page;
703
	}
704

705
706
	if ($current - 5 > 1)
		$templ_pages["..."] = false;
707

708
709
710
	for ($i = max($current - 5, 1); $i <= min($pages, $current + 5); $i++) {
		$templ_pages[$i] = ($i - 1) * $per_page;
	}
711

712
713
	if ($current + 5 < $pages)
		$templ_pages["... "] = false;
714

715
	if ($current < $pages) {
716
717
		$templ_pages[__('Next') . ' &rsaquo;'] = $current * $per_page;
		$templ_pages[__('Last') . ' &raquo;'] = ($pages - 1) * $per_page;
718
	}
Simo Leone's avatar
Simo Leone committed
719

720
	include('pkg_search_form.php');
721

canyonknight's avatar
canyonknight committed
722
723
724
725
	if ($result) {
		while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
			$searchresults[] = $row;
		}
726
727
	}

728
729
	include('pkg_search_results.php');

Loui Chang's avatar
Loui Chang committed
730
	return;
eric's avatar
eric committed
731
732
}

733
734
735
736
737
738
739
/**
 * Determine if a POST string has been sent by a visitor
 *
 * @param string $action String to check has been sent via POST
 *
 * @return bool True if the POST string was used, otherwise false
 */
Dan McGee's avatar
Dan McGee committed
740
741
742
743
744
function current_action($action) {
	return (isset($_POST['action']) && $_POST['action'] == $action) ||
		isset($_POST[$action]);
}

745
/**
746
747
748
749
750
 * Determine if sent IDs are valid integers
 *
 * @param array $ids IDs to validate
 *
 * @return array All sent IDs that are valid integers
751
752
753
754
755
756
757
758
759
760
761
762
 */
function sanitize_ids($ids) {
	$new_ids = array();
	foreach ($ids as $id) {
		$id = intval($id);
		if ($id > 0) {
			$new_ids[] = $id;
		}
	}
	return $new_ids;
}

763
764
765
/**
 * Add package information to the database for a specific package
 *
766
 * @param int $base_id ID of the package base
767
768
769
770
 * @param string $pkgname Name of the new package
 * @param string $pkgver Version of the new package
 * @param string $pkgdesc Description of the new package
 * @param string $pkgurl Upstream URL for the new package
771
772
773
 *
 * @return int ID of the new package
 */
774
function pkg_create($base_id, $pkgname, $pkgver, $pkgdesc, $pkgurl) {
775
	$dbh = DB::connect();
776
777
778
779
	$q = sprintf("INSERT INTO Packages (PackageBaseID, Name, Version, " .
		"Description, URL) VALUES (%d, %s, %s, %s, %s)",
		$base_id, $dbh->quote($pkgname), $dbh->quote($pkgver),
		$dbh->quote($pkgdesc), $dbh->quote($pkgurl));
780
781
782
783
	$dbh->exec($q);
	return $dbh->lastInsertId();
}

784
785
786
787
/**
 * Add a dependency for a specific package to the database
 *
 * @param int $pkgid The package ID to add the dependency for
788
 * @param string $type The type of dependency to add
789
790
 * @param string $depname The name of the dependency to add
 * @param string $depcondition The  type of dependency for the package
791
 * @param string $deparch The architecture of the dependency to add
792
793
794
 *
 * @return void
 */
795
function pkg_add_dep($pkgid, $type, $depname, $depcondition, $deparch) {
796
	$dbh = DB::connect();
797
	$q = sprintf("INSERT INTO PackageDepends (PackageID, DepTypeID, DepName, DepCondition, DepArch) VALUES (%d, %d, %s, %s, %s)",
798
799
800
		$pkgid,
		pkg_dependency_type_id_from_name($type),
		$dbh->quote($depname),
801
802
		$dbh->quote($depcondition),
		$deparch ? $dbh->quote($deparch) : 'NULL'
803
	);
canyonknight's avatar
canyonknight committed
804
	$dbh->exec($q);
canyonknight's avatar
canyonknight committed
805
806
}

807
808
809
810
811
812
813
/**
 * Add a relation for a specific package to the database
 *
 * @param int $pkgid The package ID to add the relation for
 * @param string $type The type of relation to add
 * @param string $relname The name of the relation to add
 * @param string $relcondition The version requirement of the relation
814
 * @param string $relarch The architecture of the relation to add
815
816
817
 *
 * @return void
 */
818
function pkg_add_rel($pkgid, $type, $relname, $relcondition, $relarch) {
819
	$dbh = DB::connect();
820
	$q = sprintf("INSERT INTO PackageRelations (PackageID, RelTypeID, RelName, RelCondition, RelArch) VALUES (%d, %d, %s, %s, %s)",
821
822
823
		$pkgid,
		pkg_relation_type_id_from_name($type),
		$dbh->quote($relname),
824
825
		$dbh->quote($relcondition),
		$relarch ? $dbh->quote($relarch) : 'NULL'
826
827
828
829
	);
	$dbh->exec($q);
}

830
831
832
833
834
/**
 * Add a source for a specific package to the database
 *
 * @param int $pkgid The package ID to add the source for
 * @param string $pkgsrc The package source to add to the database
835
 * @param string $srcarch The architecture of the source to add
836
837
838
 *
 * @return void
 */
839
function pkg_add_src($pkgid, $pkgsrc, $srcarch) {
840
	$dbh = DB::connect();
841
842
843
844
845
	$q = sprintf("INSERT INTO PackageSources (PackageID, Source, SourceArch) VALUES (%d, %s, %s)",
		$pkgid,
		$dbh->quote($pkgsrc),
		$srcarch ? $dbh->quote($srcarch) : 'NULL'
	);
canyonknight's avatar
canyonknight committed
846
	$dbh->exec($q);
canyonknight's avatar
canyonknight committed
847
}
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890

/**
 * Creates a new group and returns its ID
 *
 * If the groups already exists, the ID of the already existing group is
 * returned.
 *
 * @param string $name The name of the group to create
 *
 * @return int The ID of the group
 */
function pkg_create_group($name) {
	$dbh = DB::connect();
	$q = sprintf("SELECT ID FROM Groups WHERE Name = %s", $dbh->quote($name));
	$result = $dbh->query($q);
	if ($result) {
		$grpid = $result->fetch(PDO::FETCH_COLUMN, 0);
		if ($grpid > 0) {
			return $grpid;
		}
	}

	$q = sprintf("INSERT INTO Groups (Name) VALUES (%s)", $dbh->quote($name));
	$dbh->exec($q);
	return $dbh->lastInsertId();
}

/**
 * Add a package to a group
 *
 * @param int $pkgid The package ID of the package to add
 * @param int $grpid The group ID of the group to add the package to
 *
 * @return void
 */
function pkg_add_grp($pkgid, $grpid) {
	$dbh = DB::connect();
	$q = sprintf("INSERT INTO PackageGroups (PackageID, GroupID) VALUES (%d, %d)",
		$pkgid,
		$grpid
	);
	$dbh->exec($q);
}
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933

/**
 * Creates a new license and returns its ID
 *
 * If the license already exists, the ID of the already existing license is
 * returned.
 *
 * @param string $name The name of the license to create
 *
 * @return int The ID of the license
 */
function pkg_create_license($name) {
	$dbh = DB::connect();
	$q = sprintf("SELECT ID FROM Licenses WHERE Name = %s", $dbh->quote($name));
	$result = $dbh->query($q);
	if ($result) {
		$licid = $result->fetch(PDO::FETCH_COLUMN, 0);
		if ($licid > 0) {
			return $licid;
		}
	}

	$q = sprintf("INSERT INTO Licenses (Name) VALUES (%s)", $dbh->quote($name));
	$dbh->exec($q);
	return $dbh->lastInsertId();
}

/**
 * Add a license to a package
 *
 * @param int $pkgid The package ID of the package
 * @param int $grpid The ID of the license to add
 *
 * @return void
 */
function pkg_add_lic($pkgid, $licid) {
	$dbh = DB::connect();
	$q = sprintf("INSERT INTO PackageLicenses (PackageID, LicenseID) VALUES (%d, %d)",
		$pkgid,
		$licid
	);
	$dbh->exec($q);
}
934
935
936
937
938
939
940
941
942
943
944

/**
 * Determine package information for latest package
 *
 * @param int $numpkgs Number of packages to get information on
 *
 * @return array $packages Package info for the specified number of recent packages
 */
function latest_pkgs($numpkgs) {
	$dbh = DB::connect();

Lukas Fleischer's avatar
Lukas Fleischer committed
945
946
	$q = "SELECT Packages.*, MaintainerUID, SubmittedTS ";
	$q.= "FROM Packages LEFT JOIN PackageBases ON ";
947
	$q.= "PackageBases.ID = Packages.PackageBaseID ";
948
	$q.= "ORDER BY SubmittedTS DESC ";
949
	$q.= "LIMIT " . intval($numpkgs);
950
951
	$result = $dbh->query($q);

952
	$packages = array();
953
954
955
956
957
958
959
960
	if ($result) {
		while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
			$packages[] = $row;
		}
	}

	return $packages;
}