pkgfuncs.inc.php 25 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
182
183
184
 * @param int $pkg_id The package of the package to display the dependency for
 *
 * @return string The HTML code of the label to display
 */
185
function pkg_depend_link($name, $type, $cond, $arch, $pkg_id) {
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
	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);

204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
	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 .= ')';
		if ($type == 'optdepends') {
			$link .= ' &ndash; ' . htmlspecialchars($desc) . ' </em>';
		}
		$link .= '</em>';
228
229
230
231
	}

	return $link;
}
232

233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
/**
 * 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;
}

252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
/**
 * 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;
}

277
278
279
280
281
282
283
/**
 * 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
 */
284
function pkg_required($name="") {
285
	$deps = array();
Dan McGee's avatar
Dan McGee committed
286
	if ($name != "") {
287
		$dbh = DB::connect();
288
		$q = "SELECT DISTINCT p.Name, PackageID FROM PackageDepends pd ";
Dan McGee's avatar
Dan McGee committed
289
		$q.= "JOIN Packages p ON pd.PackageID = p.ID ";
canyonknight's avatar
canyonknight committed
290
		$q.= "WHERE DepName = " . $dbh->quote($name) . " ";
Dan McGee's avatar
Dan McGee committed
291
		$q.= "ORDER BY p.Name";
canyonknight's avatar
canyonknight committed
292
		$result = $dbh->query($q);
293
		if (!$result) {return array();}
canyonknight's avatar
canyonknight committed
294
		while ($row = $result->fetch(PDO::FETCH_NUM)) {
295
296
297
298
299
300
			$deps[] = $row;
		}
	}
	return $deps;
}

301
302
303
304
305
306
307
/**
 * 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
 */
308
function pkg_sources($pkgid) {
309
	$sources = array();
310
311
	$pkgid = intval($pkgid);
	if ($pkgid > 0) {
312
		$dbh = DB::connect();
313
		$q = "SELECT Source, SourceArch FROM PackageSources ";
314
		$q.= "WHERE PackageID = " . $pkgid;
315
		$q.= " ORDER BY Source";
canyonknight's avatar
canyonknight committed
316
317
318
319
320
		$result = $dbh->query($q);
		if (!$result) {
			return array();
		}
		while ($row = $result->fetch(PDO::FETCH_NUM)) {
321
			$sources[] = $row;
322
323
324
325
326
		}
	}
	return $sources;
}

327
328
329
330
331
332
333
/**
 * 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
 */
334
function pkg_name_from_id($pkgids) {
335
336
337
	if (is_array($pkgids)) {
		$pkgids = sanitize_ids($pkgids);
		$names = array();
338
		$dbh = DB::connect();
canyonknight's avatar
canyonknight committed
339
340
341
342
343
		$q = "SELECT Name FROM Packages WHERE ID IN (";
		$q.= implode(",", $pkgids) . ")";
		$result = $dbh->query($q);
		if ($result) {
			while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
344
345
346
347
348
349
				$names[] = $row['Name'];
			}
		}
		return $names;
	}
	elseif ($pkgids > 0) {
350
		$dbh = DB::connect();
351
		$q = "SELECT Name FROM Packages WHERE ID = " . $pkgids;
canyonknight's avatar
canyonknight committed
352
353
354
		$result = $dbh->query($q);
		if ($result) {
			$name = $result->fetch(PDO::FETCH_NUM);
355
		}
canyonknight's avatar
canyonknight committed
356
		return $name[0];
357
358
359
	}
	else {
		return NULL;
360
361
362
	}
}

363
364
365
366
367
368
369
/**
 * 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
 */
370
function pkg_name_is_blacklisted($name) {
371
	$dbh = DB::connect();
canyonknight's avatar
canyonknight committed
372
373
374
	$q = "SELECT COUNT(*) FROM PackageBlacklist ";
	$q.= "WHERE Name = " . $dbh->quote($name);
	$result = $dbh->query($q);
375
376

	if (!$result) return false;
377
	return ($result->fetchColumn() > 0);
378
379
}

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

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

404
405
	$row = array();

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

	return $row;
}

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

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

438
439
440
441
442
443
		include('pkg_details.php');

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

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

Simo Leone's avatar
Simo Leone committed
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
/* 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:
470
 *          values: n - package name
Simo Leone's avatar
Simo Leone committed
471
472
473
 *                  v - number of votes
 *                  m - maintainer username
 *    SeB- property that search string (K) represents
Andrea Scarpino's avatar
Andrea Scarpino committed
474
475
 *          values: n  - package name
 *                  nd - package name & description
476
 *                  x  - package name (exact match)
Simo Leone's avatar
Simo Leone committed
477
478
479
480
481
482
483
484
485
486
487
488
489
490
 *                  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
491
 *                     do_Delete - Delete
492
493
 *                     do_Notify - Enable notification
 *                     do_UnNotify - Disable notification
Simo Leone's avatar
Simo Leone committed
494
 */
495
function pkg_search_page($SID="") {
496
	$dbh = DB::connect();
Loui Chang's avatar
Loui Chang committed
497

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

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

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

518
519
520
521
	/*
	 * 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
522

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

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

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

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

582
			foreach (str_getcsv($_GET['K'], ' ') as $term) {
583
584
585
				if ($term == "") {
					continue;
				}
586
587
588
589
590
591
592
593
594
595
596
597
				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;
				}
598

599
				$term = "%" . addcslashes($term, '%_') . "%";
600
				$q_keywords .= $op . " (Packages.Name LIKE " . $dbh->quote($term) . " OR ";
601
602
603
604
				$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) . ")) ";
605
606
607
608
609

				$count++;
				if ($count >= 20) {
					break;
				}
610
				$op = "AND ";
611
			}
612

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

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

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

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

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

664
	$q_limit = "LIMIT ".$_GET["PP"]." OFFSET ".$_GET["O"];
665

666
667
	$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
668

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

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

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

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

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

702
703
	if ($current - 5 > 1)
		$templ_pages["..."] = false;
704

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

709
710
	if ($current + 5 < $pages)
		$templ_pages["... "] = false;
711

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

717
	include('pkg_search_form.php');
718

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

725
726
	include('pkg_search_results.php');

Loui Chang's avatar
Loui Chang committed
727
	return;
eric's avatar
eric committed
728
729
}

730
731
732
733
734
735
736
/**
 * 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
737
738
739
740
741
function current_action($action) {
	return (isset($_POST['action']) && $_POST['action'] == $action) ||
		isset($_POST[$action]);
}

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

760
761
762
/**
 * Add package information to the database for a specific package
 *
763
 * @param int $base_id ID of the package base
764
765
766
767
 * @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
768
769
770
 *
 * @return int ID of the new package
 */
771
function pkg_create($base_id, $pkgname, $pkgver, $pkgdesc, $pkgurl) {
772
	$dbh = DB::connect();
773
774
775
776
	$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));
777
778
779
780
	$dbh->exec($q);
	return $dbh->lastInsertId();
}

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

804
805
806
807
808
809
810
/**
 * 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
811
 * @param string $relarch The architecture of the relation to add
812
813
814
 *
 * @return void
 */
815
function pkg_add_rel($pkgid, $type, $relname, $relcondition, $relarch) {
816
	$dbh = DB::connect();
817
	$q = sprintf("INSERT INTO PackageRelations (PackageID, RelTypeID, RelName, RelCondition, RelArch) VALUES (%d, %d, %s, %s, %s)",
818
819
820
		$pkgid,
		pkg_relation_type_id_from_name($type),
		$dbh->quote($relname),
821
822
		$dbh->quote($relcondition),
		$relarch ? $dbh->quote($relarch) : 'NULL'
823
824
825
826
	);
	$dbh->exec($q);
}

827
828
829
830
831
/**
 * 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
832
 * @param string $srcarch The architecture of the source to add
833
834
835
 *
 * @return void
 */
836
function pkg_add_src($pkgid, $pkgsrc, $srcarch) {
837
	$dbh = DB::connect();
838
839
840
841
842
	$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
843
	$dbh->exec($q);
canyonknight's avatar
canyonknight committed
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
877
878
879
880
881
882
883
884
885
886
887

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

/**
 * 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);
}
931
932
933
934
935
936
937
938
939
940
941

/**
 * 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
942
943
	$q = "SELECT Packages.*, MaintainerUID, SubmittedTS ";
	$q.= "FROM Packages LEFT JOIN PackageBases ON ";
944
	$q.= "PackageBases.ID = Packages.PackageBaseID ";
945
	$q.= "ORDER BY SubmittedTS DESC ";
946
	$q.= "LIMIT " . intval($numpkgs);
947
948
	$result = $dbh->query($q);

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

	return $packages;
}