pkgfuncs.inc.php 23.7 KB
Newer Older
1
<?php
2
include_once("config.inc.php");
3
include_once("pkgbasefuncs.inc.php");
eric's avatar
eric committed
4

5
6
7
8
9
10
11
12
13
14
15
16
/**
 * 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
 * @param string $atype The account type of the user trying to delete a comment
 * @param string|int $uid The user ID of the individual trying to delete a comment
 *
 * @return bool True if the user can delete the comment, otherwise false
 */
17
function can_delete_comment($comment_id=0, $atype="", $uid=0) {
18
19
20
21
	if (!$uid) {
		/* Unauthenticated users cannot delete anything. */
		return false;
	}
22
	if ($atype == "Trusted User" || $atype == "Developer") {
23
		/* TUs and developers can delete any comment. */
24
		return true;
25
	}
Lukas Fleischer's avatar
Lukas Fleischer committed
26

27
	$dbh = DB::connect();
Lukas Fleischer's avatar
Lukas Fleischer committed
28
29
30

	$q = "SELECT COUNT(*) FROM PackageComments ";
	$q.= "WHERE ID = " . intval($comment_id) . " AND UsersID = " . $uid;
canyonknight's avatar
canyonknight committed
31
	$result = $dbh->query($q);
Lukas Fleischer's avatar
Lukas Fleischer committed
32
33
34

	if (!$result) {
		return false;
35
	}
Lukas Fleischer's avatar
Lukas Fleischer committed
36
37
38

	$row = $result->fetch(PDO::FETCH_NUM);
	return ($row[0] > 0);
39
}
eric's avatar
eric committed
40

41
42
43
44
45
46
47
48
49
50
51
52
/**
 * 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
 * @param string $atype The account type of the user trying to delete a comment
 * @param string|int $uid The user ID of the individual trying to delete a comment
 *
 * @return bool True if the user can delete the comment, otherwise false
 */
53
function can_delete_comment_array($comment, $atype="", $uid=0) {
54
55
56
57
	if (!$uid) {
		/* Unauthenticated users cannot delete anything. */
		return false;
	} elseif ($atype == "Trusted User" || $atype == "Developer") {
58
		/* TUs and developers can delete any comment. */
59
		return true;
60
	} else if ($comment['UsersID'] == $uid) {
61
		/* Users can delete their own comments. */
62
		return true;
63
	}
64
	return false;
65
66
}

67
68
69
70
71
72
73
74
75
76
/**
 * Determine if the visitor can submit blacklisted packages.
 *
 * Only Trusted Users and Developers can delete blacklisted packages. Packages
 * are blacklisted if they are include in the official repositories.
 *
 * @param string $atype The account type of the user
 *
 * @return bool True if the user can submit blacklisted packages, otherwise false
 */
77
function can_submit_blacklisted($atype = "") {
78
	if ($atype == "Trusted User" || $atype == "Developer") {
79
		/* Only TUs and developers can submit blacklisted packages. */
80
		return true;
81
82
	}
	else {
83
		return false;
84
85
86
	}
}

87
88
89
90
91
92
93
/**
 * 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
 */
94
function pkg_from_name($name="") {
95
	if (!$name) {return NULL;}
96
	$dbh = DB::connect();
97
	$q = "SELECT ID FROM Packages ";
canyonknight's avatar
canyonknight committed
98
99
100
101
102
103
	$q.= "WHERE Name = " . $dbh->quote($name);
	$result = $dbh->query($q);
	if (!$result) {
		return;
	}
	$row = $result->fetch(PDO::FETCH_NUM);
104
105
106
	return $row[0];
}

107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/**
 * 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;
}

133
134
135
136
137
138
139
/**
 * Get package dependencies for a specific package
 *
 * @param int $pkgid The package to get dependencies for
 *
 * @return array All package dependencies for the package
 */
140
function pkg_dependencies($pkgid) {
141
	$deps = array();
142
143
	$pkgid = intval($pkgid);
	if ($pkgid > 0) {
144
		$dbh = DB::connect();
145
		$q = "SELECT pd.DepName, dt.Name, pd.DepCondition, p.ID FROM PackageDepends pd ";
Dan McGee's avatar
Dan McGee committed
146
		$q.= "LEFT JOIN Packages p ON pd.DepName = p.Name ";
147
		$q.= "LEFT JOIN DependencyTypes dt ON dt.ID = pd.DepTypeID ";
Dan McGee's avatar
Dan McGee committed
148
149
		$q.= "WHERE pd.PackageID = ". $pkgid . " ";
		$q.= "ORDER BY pd.DepName";
canyonknight's avatar
canyonknight committed
150
151
152
153
154
		$result = $dbh->query($q);
		if (!$result) {
			return array();
		}
		while ($row = $result->fetch(PDO::FETCH_NUM)) {
155
156
157
158
159
160
			$deps[] = $row;
		}
	}
	return $deps;
}

161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/**
 * 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();
		$q = "SELECT pr.RelName, rt.Name, pr.RelCondition, p.ID FROM PackageRelations pr ";
		$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;
}

189
190
191
192
193
194
195
196
197
198
199
200
201
202
/**
 * Get the ID of a dependency type given its name
 *
 * @param string $name The name of the dependency type
 *
 * @return int The ID of the dependency type
 */
function pkg_dependency_type_id_from_name($name) {
	$dbh = DB::connect();
	$q = "SELECT ID FROM DependencyTypes WHERE Name = ";
	$q.= $dbh->quote($name);
	$result = $dbh->query($q);
	return $result->fetch(PDO::FETCH_COLUMN, 0);
}
203

204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
/**
 * Get the ID of a relation type given its name
 *
 * @param string $name The name of the relation type
 *
 * @return int The ID of the relation type
 */
function pkg_relation_type_id_from_name($name) {
	$dbh = DB::connect();
	$q = "SELECT ID FROM RelationTypes WHERE Name = ";
	$q.= $dbh->quote($name);
	$result = $dbh->query($q);
	return $result->fetch(PDO::FETCH_COLUMN, 0);
}

219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
/**
 * 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
 * @param int $pkg_id The package of the package to display the dependency for
 *
 * @return string The HTML code of the label to display
 */
function pkg_depend_link($name, $type, $cond, $pkg_id) {
	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);

	if ($type == 'makedepends') {
		$link .= ' <em>(make)</em>';
	} elseif ($type == 'checkdepends') {
		$link .= ' <em>(check)</em>';
	} elseif ($type == 'optdepends') {
		$link .= ' <em>(optional) &ndash; ' . htmlspecialchars($desc) . ' </em>';
	}

	return $link;
}
258

259
260
261
262
263
264
265
/**
 * 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
 */
266
function pkg_required($name="") {
267
	$deps = array();
Dan McGee's avatar
Dan McGee committed
268
	if ($name != "") {
269
		$dbh = DB::connect();
270
		$q = "SELECT DISTINCT p.Name, PackageID FROM PackageDepends pd ";
Dan McGee's avatar
Dan McGee committed
271
		$q.= "JOIN Packages p ON pd.PackageID = p.ID ";
canyonknight's avatar
canyonknight committed
272
		$q.= "WHERE DepName = " . $dbh->quote($name) . " ";
Dan McGee's avatar
Dan McGee committed
273
		$q.= "ORDER BY p.Name";
canyonknight's avatar
canyonknight committed
274
		$result = $dbh->query($q);
275
		if (!$result) {return array();}
canyonknight's avatar
canyonknight committed
276
		while ($row = $result->fetch(PDO::FETCH_NUM)) {
277
278
279
280
281
282
			$deps[] = $row;
		}
	}
	return $deps;
}

283
284
285
286
287
288
289
/**
 * 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
 */
290
function pkg_sources($pkgid) {
291
	$sources = array();
292
293
	$pkgid = intval($pkgid);
	if ($pkgid > 0) {
294
		$dbh = DB::connect();
295
		$q = "SELECT Source FROM PackageSources ";
296
		$q.= "WHERE PackageID = " . $pkgid;
297
		$q.= " ORDER BY Source";
canyonknight's avatar
canyonknight committed
298
299
300
301
302
		$result = $dbh->query($q);
		if (!$result) {
			return array();
		}
		while ($row = $result->fetch(PDO::FETCH_NUM)) {
303
304
305
306
307
308
			$sources[] = $row[0];
		}
	}
	return $sources;
}

309
310
311
312
313
314
315
/**
 * 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
 */
316
function pkg_name_from_id($pkgids) {
317
318
319
	if (is_array($pkgids)) {
		$pkgids = sanitize_ids($pkgids);
		$names = array();
320
		$dbh = DB::connect();
canyonknight's avatar
canyonknight committed
321
322
323
324
325
		$q = "SELECT Name FROM Packages WHERE ID IN (";
		$q.= implode(",", $pkgids) . ")";
		$result = $dbh->query($q);
		if ($result) {
			while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
326
327
328
329
330
331
				$names[] = $row['Name'];
			}
		}
		return $names;
	}
	elseif ($pkgids > 0) {
332
		$dbh = DB::connect();
333
		$q = "SELECT Name FROM Packages WHERE ID = " . $pkgids;
canyonknight's avatar
canyonknight committed
334
335
336
		$result = $dbh->query($q);
		if ($result) {
			$name = $result->fetch(PDO::FETCH_NUM);
337
		}
canyonknight's avatar
canyonknight committed
338
		return $name[0];
339
340
341
	}
	else {
		return NULL;
342
343
344
	}
}

345
346
347
348
349
350
351
/**
 * 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
 */
352
function pkg_name_is_blacklisted($name) {
353
	$dbh = DB::connect();
canyonknight's avatar
canyonknight committed
354
355
356
	$q = "SELECT COUNT(*) FROM PackageBlacklist ";
	$q.= "WHERE Name = " . $dbh->quote($name);
	$result = $dbh->query($q);
357
358

	if (!$result) return false;
359
	return ($result->fetchColumn() > 0);
360
361
}

362
/**
363
 * Get the package details
364
 *
365
 * @param string $id The package ID to get description for
366
 *
367
368
 * @return array The package's details OR error message
 **/
369
function pkg_get_details($id=0) {
370
	$dbh = DB::connect();
371

372
373
374
375
376
377
378
379
	$q = "SELECT Packages.*, PackageBases.Name AS BaseName, ";
	$q.= "PackageBases.CategoryID, PackageBases.NumVotes, ";
	$q.= "PackageBases.OutOfDateTS, PackageBases.SubmittedTS, ";
	$q.= "PackageBases.ModifiedTS, PackageBases.SubmitterUID, ";
	$q.= "PackageBases.MaintainerUID, PackageCategories.Category ";
	$q.= "FROM Packages, PackageBases, PackageCategories ";
	$q.= "WHERE PackageBases.ID = Packages.PackageBaseID ";
	$q.= "AND PackageBases.CategoryID = PackageCategories.ID ";
Loui Chang's avatar
Loui Chang committed
380
	$q.= "AND Packages.ID = " . intval($id);
canyonknight's avatar
canyonknight committed
381
	$result = $dbh->query($q);
eric's avatar
eric committed
382

383
384
	$row = array();

canyonknight's avatar
canyonknight committed
385
	if (!$result) {
386
		$row['error'] = __("Error retrieving package details.");
387
388
	}
	else {
canyonknight's avatar
canyonknight committed
389
		$row = $result->fetch(PDO::FETCH_ASSOC);
eric's avatar
eric committed
390
		if (empty($row)) {
391
			$row['error'] = __("Package details could not be found.");
392
		}
393
394
395
396
397
398
399
400
401
402
403
	}

	return $row;
}

/**
 * Display the package details page
 *
 * @global string $AUR_LOCATION The AUR's URL used for notification e-mails
 * @global bool $USE_VIRTUAL_URLS True if using URL rewriting, otherwise false
 * @param string $id The package ID to get details page for
404
 * @param array $row Package details retrieved by pkg_get_details()
405
406
407
408
 * @param string $SID The session ID of the visitor
 *
 * @return void
 */
409
function pkg_display_details($id=0, $row, $SID="") {
410
411
412
	global $AUR_LOCATION;
	global $USE_VIRTUAL_URLS;

413
	$dbh = DB::connect();
414

415
416
417
418
	if (isset($row['error'])) {
		print "<p>" . $row['error'] . "</p>\n";
	}
	else {
419
420
421
		$base_id = pkgbase_from_pkgid($id);
		$pkgbase_name = pkgbase_name_from_id($base_id);

422
423
424
425
426
427
428
		include('pkg_details.php');

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

Lukas Fleischer's avatar
Lukas Fleischer committed
429
430
		$limit = isset($_GET['comments']) ? 0 : 10;
		$comments = pkgbase_comments($base_id, $limit);
431
432
		if (!empty($comments)) {
			include('pkg_comments.php');
eric's avatar
eric committed
433
434
435
436
		}
	}
}

Simo Leone's avatar
Simo Leone committed
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
/* 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
 *    C  - package category ID number
 *    K  - package search string
 *    SO - search hit sort order:
 *          values: a - ascending
 *                  d - descending
 *    SB - sort search hits by:
455
 *          values: c - package category
Simo Leone's avatar
Simo Leone committed
456
457
458
459
 *                  n - package name
 *                  v - number of votes
 *                  m - maintainer username
 *    SeB- property that search string (K) represents
Andrea Scarpino's avatar
Andrea Scarpino committed
460
461
 *          values: n  - package name
 *                  nd - package name & description
462
 *                  x  - package name (exact match)
Simo Leone's avatar
Simo Leone committed
463
464
465
466
467
468
469
470
471
472
473
474
475
476
 *                  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
477
 *                     do_Delete - Delete (requires confirm_Delete to be set)
478
479
 *                     do_Notify - Enable notification
 *                     do_UnNotify - Disable notification
Simo Leone's avatar
Simo Leone committed
480
 */
481
function pkg_search_page($SID="") {
482
	$dbh = DB::connect();
Loui Chang's avatar
Loui Chang committed
483

484
485
486
487
	/*
	 * Get commonly used variables.
	 * TODO: Reduce the number of database queries!
	 */
Loui Chang's avatar
Loui Chang committed
488
	if ($SID)
489
		$myuid = uid_from_sid($SID);
490
	$cats = pkgbase_categories($dbh);
Loui Chang's avatar
Loui Chang committed
491

492
	/* Sanitize paging variables. */
Loui Chang's avatar
Loui Chang committed
493
494
495
496
497
498
499
500
501
502
503
	if (isset($_GET['O'])) {
		$_GET['O'] = intval($_GET['O']);
		if ($_GET['O'] < 0)
			$_GET['O'] = 0;
	}
	else {
		$_GET['O'] = 0;
	}

	if (isset($_GET["PP"])) {
		$_GET["PP"] = intval($_GET["PP"]);
504
505
506
507
		if ($_GET["PP"] < 50)
			$_GET["PP"] = 50;
		else if ($_GET["PP"] > 250)
			$_GET["PP"] = 250;
Loui Chang's avatar
Loui Chang committed
508
509
	}
	else {
510
		$_GET["PP"] = 50;
Loui Chang's avatar
Loui Chang committed
511
512
	}

513
514
515
516
	/*
	 * 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
517

518
	/* Build the package search query. */
519
	$q_select = "SELECT ";
Loui Chang's avatar
Loui Chang committed
520
	if ($SID) {
521
		$q_select .= "CommentNotify.UserID AS Notify,
522
			   PackageVotes.UsersID AS Voted, ";
Loui Chang's avatar
Loui Chang committed
523
	}
524
	$q_select .= "Users.Username AS Maintainer,
Loui Chang's avatar
Loui Chang committed
525
	PackageCategories.Category,
526
	Packages.Name, Packages.Version, Packages.Description,
527
528
	PackageBases.NumVotes, Packages.ID, Packages.PackageBaseID,
	PackageBases.OutOfDateTS ";
Loui Chang's avatar
Loui Chang committed
529

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

Dan McGee's avatar
Dan McGee committed
545
	$q_where = "WHERE 1 = 1 ";
546
547
548
549
	/*
	 * TODO: Possibly do string matching on category to make request
	 * variable values more sensible.
	 */
550
	if (isset($_GET["C"]) && intval($_GET["C"])) {
Lukas Fleischer's avatar
Lukas Fleischer committed
551
		$q_where .= "AND PackageBases.CategoryID = ".intval($_GET["C"])." ";
Loui Chang's avatar
Loui Chang committed
552
553
	}

554
555
	if (isset($_GET['K'])) {
		if (isset($_GET["SeB"]) && $_GET["SeB"] == "m") {
556
			/* Search by maintainer. */
canyonknight's avatar
canyonknight committed
557
			$q_where .= "AND Users.Username = " . $dbh->quote($_GET['K']) . " ";
Loui Chang's avatar
Loui Chang committed
558
		}
559
		elseif (isset($_GET["SeB"]) && $_GET["SeB"] == "s") {
560
			/* Search by submitter. */
561
			$q_where .= "AND SubmitterUID = ".uid_from_username($_GET['K'])." ";
Loui Chang's avatar
Loui Chang committed
562
		}
563
		elseif (isset($_GET["SeB"]) && $_GET["SeB"] == "n") {
564
			/* Search by name. */
canyonknight's avatar
canyonknight committed
565
			$K = "%" . addcslashes($_GET['K'], '%_') . "%";
566
			$q_where .= "AND (Packages.Name LIKE " . $dbh->quote($K) . ") ";
Andrea Scarpino's avatar
Andrea Scarpino committed
567
		}
568
569
570
571
572
573
		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") {
574
			/* Search by name (exact match). */
575
			$q_where .= "AND (Packages.Name = " . $dbh->quote($_GET['K']) . ") ";
576
		}
577
578
579
580
		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
581
		else {
582
			/* Search by name and description (default). */
canyonknight's avatar
canyonknight committed
583
			$K = "%" . addcslashes($_GET['K'], '%_') . "%";
584
			$q_where .= "AND (Packages.Name LIKE " . $dbh->quote($K) . " OR ";
canyonknight's avatar
canyonknight committed
585
			$q_where .= "Description LIKE " . $dbh->quote($K) . ") ";
Loui Chang's avatar
Loui Chang committed
586
587
588
		}
	}

589
	if (isset($_GET["do_Orphans"])) {
590
		$q_where .= "AND MaintainerUID IS NULL ";
Loui Chang's avatar
Loui Chang committed
591
	}
592

593
	if (isset($_GET['outdated'])) {
594
		if ($_GET['outdated'] == 'on') {
595
			$q_where .= "AND OutOfDateTS IS NOT NULL ";
596
597
		}
		elseif ($_GET['outdated'] == 'off') {
598
			$q_where .= "AND OutOfDateTS IS NULL ";
599
		}
600
601
	}

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

604
	$q_sort = "ORDER BY ";
605
606
	$sort_by = isset($_GET["SB"]) ? $_GET["SB"] : '';
	switch ($sort_by) {
Loui Chang's avatar
Loui Chang committed
607
	case 'c':
608
		$q_sort .= "CategoryID " . $order . ", ";
Loui Chang's avatar
Loui Chang committed
609
610
		break;
	case 'v':
611
		$q_sort .= "NumVotes " . $order . ", ";
Loui Chang's avatar
Loui Chang committed
612
		break;
613
614
	case 'w':
		if ($SID) {
615
			$q_sort .= "Voted " . $order . ", ";
616
617
618
619
		}
		break;
	case 'o':
		if ($SID) {
620
			$q_sort .= "Notify " . $order . ", ";
621
622
		}
		break;
Loui Chang's avatar
Loui Chang committed
623
	case 'm':
624
		$q_sort .= "Maintainer " . $order . ", ";
Loui Chang's avatar
Loui Chang committed
625
626
		break;
	case 'a':
627
		$q_sort .= "ModifiedTS " . $order . ", ";
Loui Chang's avatar
Loui Chang committed
628
629
630
631
		break;
	default:
		break;
	}
632
	$q_sort .= " Packages.Name " . $order . " ";
Loui Chang's avatar
Loui Chang committed
633

634
	$q_limit = "LIMIT ".$_GET["PP"]." OFFSET ".$_GET["O"];
635

636
637
	$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
638

canyonknight's avatar
canyonknight committed
639
640
	$result = $dbh->query($q);
	$result_t = $dbh->query($q_total);
641
	if ($result_t) {
canyonknight's avatar
canyonknight committed
642
643
		$row = $result_t->fetch(PDO::FETCH_NUM);
		$total = $row[0];
644
645
646
647
	}
	else {
		$total = 0;
	}
Simo Leone's avatar
Simo Leone committed
648

649
	if ($result && $total > 0) {
650
651
		if (isset($_GET["SO"]) && $_GET["SO"] == "d"){
			$SO_next = "a";
Loui Chang's avatar
Loui Chang committed
652
653
		}
		else {
654
			$SO_next = "d";
Loui Chang's avatar
Loui Chang committed
655
		}
656
	}
Simo Leone's avatar
Simo Leone committed
657

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

661
	/* Calculation of pagination links. */
662
663
664
665
	$per_page = ($_GET['PP'] > 0) ? $_GET['PP'] : 50;
	$current = ceil($first / $per_page);
	$pages = ceil($total / $per_page);
	$templ_pages = array();
666

667
	if ($current > 1) {
668
669
		$templ_pages['&laquo; ' . __('First')] = 0;
		$templ_pages['&lsaquo; ' . __('Previous')] = ($current - 2) * $per_page;
670
	}
671

672
673
	if ($current - 5 > 1)
		$templ_pages["..."] = false;
674

675
676
677
	for ($i = max($current - 5, 1); $i <= min($pages, $current + 5); $i++) {
		$templ_pages[$i] = ($i - 1) * $per_page;
	}
678

679
680
	if ($current + 5 < $pages)
		$templ_pages["... "] = false;
681

682
	if ($current < $pages) {
683
684
		$templ_pages[__('Next') . ' &rsaquo;'] = $current * $per_page;
		$templ_pages[__('Last') . ' &raquo;'] = ($pages - 1) * $per_page;
685
	}
Simo Leone's avatar
Simo Leone committed
686

687
	include('pkg_search_form.php');
688

canyonknight's avatar
canyonknight committed
689
690
691
692
	if ($result) {
		while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
			$searchresults[] = $row;
		}
693
694
	}

695
696
	include('pkg_search_results.php');

Loui Chang's avatar
Loui Chang committed
697
	return;
eric's avatar
eric committed
698
699
}

700
701
702
703
704
705
706
/**
 * 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
707
708
709
710
711
function current_action($action) {
	return (isset($_POST['action']) && $_POST['action'] == $action) ||
		isset($_POST[$action]);
}

712
/**
713
714
715
716
717
 * Determine if sent IDs are valid integers
 *
 * @param array $ids IDs to validate
 *
 * @return array All sent IDs that are valid integers
718
719
720
721
722
723
724
725
726
727
728
729
 */
function sanitize_ids($ids) {
	$new_ids = array();
	foreach ($ids as $id) {
		$id = intval($id);
		if ($id > 0) {
			$new_ids[] = $id;
		}
	}
	return $new_ids;
}

730
731
732
733
734
735
736
/**
 * Get all package information in the database for a specific package
 *
 * @param string $pkgname The name of the package to get details for
 *
 * @return array All package details for a specific package
 */
737
function pkg_details_by_name($pkgname) {
738
	$dbh = DB::connect();
739
740
741
742
743
744
745
746
	$q = "SELECT Packages.*, PackageBases.Name AS BaseName, ";
	$q.= "PackageBases.CategoryID, PackageBases.NumVotes, ";
	$q.= "PackageBases.OutOfDateTS, PackageBases.SubmittedTS, ";
	$q.= "PackageBases.ModifiedTS, PackageBases.SubmitterUID, ";
	$q.= "PackageBases.MaintainerUID FROM Packages ";
	$q.= "INNER JOIN PackageBases ";
	$q.= "ON PackageBases.ID = Packages.PackageBaseID WHERE ";
	$q.= "Packages.Name = " . $dbh->quote($pkgname);
canyonknight's avatar
canyonknight committed
747
	$result = $dbh->query($q);
canyonknight's avatar
canyonknight committed
748
	if ($result) {
canyonknight's avatar
canyonknight committed
749
		$row = $result->fetch(PDO::FETCH_ASSOC);
canyonknight's avatar
canyonknight committed
750
	}
canyonknight's avatar
canyonknight committed
751
	return $row;
canyonknight's avatar
canyonknight committed
752
753
}

754
755
756
/**
 * Add package information to the database for a specific package
 *
757
 * @param int $base_id ID of the package base
758
759
760
761
762
 * @param string $pkgname Name of the new package
 * @param string $license License 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
763
764
765
 *
 * @return int ID of the new package
 */
766
function pkg_create($base_id, $pkgname, $license, $pkgver, $pkgdesc, $pkgurl) {
767
768
769
770
771
772
773
774
775
776
	$dbh = DB::connect();
	$q = sprintf("INSERT INTO Packages (PackageBaseID, Name, License, " .
		"Version, Description, URL) VALUES (%d, %s, %s, %s, %s, %s)",
		$base_id, $dbh->quote($pkgname), $dbh->quote($license),
		$dbh->quote($pkgver), $dbh->quote($pkgdesc),
		$dbh->quote($pkgurl));
	$dbh->exec($q);
	return $dbh->lastInsertId();
}

777
778
779
780
/**
 * Add a dependency for a specific package to the database
 *
 * @param int $pkgid The package ID to add the dependency for
781
 * @param string $type The type of dependency to add
782
783
784
785
786
 * @param string $depname The name of the dependency to add
 * @param string $depcondition The  type of dependency for the package
 *
 * @return void
 */
787
function pkg_add_dep($pkgid, $type, $depname, $depcondition) {
788
	$dbh = DB::connect();
789
790
791
792
793
794
	$q = sprintf("INSERT INTO PackageDepends (PackageID, DepTypeID, DepName, DepCondition) VALUES (%d, %d, %s, %s)",
		$pkgid,
		pkg_dependency_type_id_from_name($type),
		$dbh->quote($depname),
		$dbh->quote($depcondition)
	);
canyonknight's avatar
canyonknight committed
795
	$dbh->exec($q);
canyonknight's avatar
canyonknight committed
796
797
}

798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
/**
 * 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
 *
 * @return void
 */
function pkg_add_rel($pkgid, $type, $relname, $relcondition) {
	$dbh = DB::connect();
	$q = sprintf("INSERT INTO PackageRelations (PackageID, RelTypeID, RelName, RelCondition) VALUES (%d, %d, %s, %s)",
		$pkgid,
		pkg_relation_type_id_from_name($type),
		$dbh->quote($relname),
		$dbh->quote($relcondition)
	);
	$dbh->exec($q);
}

819
820
821
822
823
824
825
826
/**
 * 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
 *
 * @return void
 */
827
function pkg_add_src($pkgid, $pkgsrc) {
828
	$dbh = DB::connect();
canyonknight's avatar
canyonknight committed
829
	$q = "INSERT INTO PackageSources (PackageID, Source) VALUES (";
canyonknight's avatar
canyonknight committed
830
	$q .= $pkgid . ", " . $dbh->quote($pkgsrc) . ")";
canyonknight's avatar
canyonknight committed
831

canyonknight's avatar
canyonknight committed
832
	$dbh->exec($q);
canyonknight's avatar
canyonknight committed
833
}
834
835
836
837
838
839
840
841
842
843
844
845
846
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

/**
 * 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);
}