aboutsummaryrefslogtreecommitdiff
path: root/php
diff options
context:
space:
mode:
authorBrian Evans <grknight@gentoo.org>2018-01-29 16:04:13 -0500
committerBrian Evans <grknight@gentoo.org>2018-01-29 16:05:35 -0500
commit3c56284f7fe1926f6bf6ebd97ec72805d94df1e4 (patch)
tree805a3fb4cfb14519c0bebc3f1863f4759e916a82 /php
downloadbouncer-3c56284f7fe1926f6bf6ebd97ec72805d94df1e4.tar.gz
bouncer-3c56284f7fe1926f6bf6ebd97ec72805d94df1e4.tar.bz2
bouncer-3c56284f7fe1926f6bf6ebd97ec72805d94df1e4.zip
Import existing bouncer.g.o into gitv1.0-20181208-IMPORT
Diffstat (limited to 'php')
-rw-r--r--php/admin/index.php111
-rw-r--r--php/admin/locations.php100
-rw-r--r--php/admin/login.php42
-rw-r--r--php/admin/logout.php12
-rw-r--r--php/admin/lstats.php59
-rw-r--r--php/admin/mirror-list.php74
-rw-r--r--php/admin/mstats.php32
-rw-r--r--php/admin/os.php100
-rw-r--r--php/admin/products.php101
-rw-r--r--php/admin/pstats.php29
-rw-r--r--php/admin/regions.php101
-rw-r--r--php/admin/users.php104
-rw-r--r--php/cfg/admin_init.php15
-rw-r--r--php/cfg/config-dist.php18
-rw-r--r--php/cfg/init.php18
-rw-r--r--php/css/print.css0
-rw-r--r--php/css/screen.css84
-rw-r--r--php/images/gridtest.gifbin0 -> 3199 bytes
-rw-r--r--php/images/gtop-www.jpgbin0 -> 4551 bytes
-rw-r--r--php/img/down.gifbin0 -> 57 bytes
-rw-r--r--php/img/up.gifbin0 -> 57 bytes
-rw-r--r--php/inc/admin_nav.php27
-rw-r--r--php/inc/footer.php24
-rw-r--r--php/inc/forms/location.php23
-rw-r--r--php/inc/forms/mirror.php27
-rw-r--r--php/inc/forms/os.php16
-rw-r--r--php/inc/forms/product.php16
-rw-r--r--php/inc/forms/region.php16
-rw-r--r--php/inc/forms/user.php37
-rw-r--r--php/inc/header.php55
-rw-r--r--php/inc/nav.php0
-rw-r--r--php/index-list.php83
-rw-r--r--php/index.php75
-rw-r--r--php/index.php.orig79
-rw-r--r--php/lib/auth.php75
-rw-r--r--php/lib/csv.php216
-rw-r--r--php/lib/db.php298
-rw-r--r--php/lib/db.php.orig306
-rw-r--r--php/lib/forms.php659
-rw-r--r--php/lib/geo.php69
-rw-r--r--php/lib/list.php391
-rw-r--r--php/lib/mirror.php531
-rw-r--r--php/lib/util.php322
-rw-r--r--php/mozilla.js22
-rw-r--r--php/rss/download-counts.php55
45 files changed, 4422 insertions, 0 deletions
diff --git a/php/admin/index.php b/php/admin/index.php
new file mode 100644
index 0000000..8c3db5c
--- /dev/null
+++ b/php/admin/index.php
@@ -0,0 +1,111 @@
+<?php
+/**
+ * Regions.
+ * @package mirror
+ * @subpackage admin
+ */
+$protect=1; // protect this page
+require_once('../cfg/init.php');
+
+// add mirror
+if (!empty($_POST['add-submit'])) {
+ if (mirror_insert_mirror($_POST['mirror_name'],$_POST['region_id'],$_POST['mirror_baseurl'],$_POST['mirror_rating'])) {
+ set_msg('Mirror added successfully.');
+ header('Location: http://'.$_SERVER['HTTP_HOST'].WEBPATH.'/admin/');
+ exit;
+ } else {
+ set_error('Mirror could not be added because of an unknown error.');
+ }
+}
+
+// process actions
+if (!empty($_POST['submit'])) {
+ if (!empty($_POST['mirror_id'])) {
+ switch($_POST['action']) {
+ case 'edit':
+ if (!empty($_POST['doit'])) {
+ if (mirror_update_mirror($_POST['mirror_id'],$_POST['mirror_name'],$_POST['region_id'],$_POST['mirror_baseurl'],$_POST['mirror_rating'])) {
+ set_msg('Mirror updated successfully.');
+ header('Location: http://'.$_SERVER['HTTP_HOST'].WEBPATH.'/admin/');
+ exit;
+ } else {
+ set_error('Mirror update failed.');
+ }
+ } else {
+ $title = 'Edit Mirror';
+ $nav = INC.'/admin_nav.php';
+ require_once(HEADER);
+ echo '<h2>Edit Mirror</h2>';
+ $posts = mirror_get_one_mirror($_POST['mirror_id']);
+ form_start();
+ include_once(INC.'/forms/mirror.php');
+ form_hidden('doit','1');
+ form_hidden('action','edit');
+ form_hidden('mirror_id',$_POST['mirror_id']);
+ form_submit('submit','','button1','Update');
+ form_end();
+ require_once(FOOTER);
+ exit;
+ }
+ break;
+ case 'delete':
+ if (mirror_delete_mirror($_POST['mirror_id'])) {
+ set_msg('Mirror deleted successfully.');
+ } else {
+ set_error('Mirror could not be deleted.');
+ }
+ break;
+ case 'toggle':
+ if (mirror_toggle($_POST['mirror_id'])) {
+ set_msg('Mirror enabled/disabled.');
+ } else {
+ set_error('Mirror could not be enabled/disabled.');
+ }
+ }
+ } else {
+ set_error('You must select a mirror to continue.');
+ }
+}
+
+$title = 'Mirrors';
+$nav = INC.'/admin_nav.php';
+require_once(HEADER);
+echo '<h2>Mirrors</h2>';
+
+show_error();
+show_msg();
+
+$mirrors = mirror_get_mirrors();
+
+$_GET['sort']=(!empty($_GET['sort']))?$_GET['sort']:'mirror_active';
+$_GET['order']=(!empty($_GET['order']))?$_GET['order']:'ASC';
+$mirrors=array_order_by($mirrors,$_GET['sort'],$_GET['order']);
+
+$headers = array(
+ 'mirror_id'=>'',
+ 'mirror_active'=>'Status',
+ 'mirror_rating'=>'Rating',
+ 'mirror_name'=>'Host Name',
+ 'mirror_baseurl'=>'Address',
+ 'region_name'=>'Region',
+ 'mirror_count'=>'Hits'
+);
+
+$actions = array(
+ 'toggle'=>'Enable/Disable',
+ 'edit'=>'Edit',
+ 'delete'=>'Delete'
+);
+
+form_start();
+show_list($mirrors,$headers,'radio',$actions);
+form_end();
+
+echo '<h2>Add a Mirror</h2>';
+form_start();
+include_once(INC.'/forms/mirror.php');
+form_submit('add-submit','','button1','Add Mirror');
+form_end();
+
+require_once(FOOTER);
+?>
diff --git a/php/admin/locations.php b/php/admin/locations.php
new file mode 100644
index 0000000..f1bb456
--- /dev/null
+++ b/php/admin/locations.php
@@ -0,0 +1,100 @@
+<?php
+/**
+ * File locations.
+ * @package mirror
+ * @subpackage admin
+ */
+$protect=1; // protect this page
+require_once('../cfg/init.php');
+
+// add mirror
+if (!empty($_POST['add-submit'])&&!empty($_POST['location_path'])) {
+ if (mirror_insert_location($_POST['product_id'],$_POST['os_id'],$_POST['location_path'])) {
+ set_msg('Location added successfully.');
+ header('Location: http://'.$_SERVER['HTTP_HOST'].WEBPATH.'/admin/locations.php');
+ exit;
+ } else {
+ set_error('Location could not be added because of an unknown error.');
+ }
+}
+
+// process actions
+if (!empty($_POST['submit'])) {
+ if (!empty($_POST['location_id'])) {
+ switch($_POST['action']) {
+ case 'edit':
+ if (!empty($_POST['doit'])) {
+ if (mirror_update_location($_POST['location_id'],$_POST['product_id'],$_POST['os_id'],$_POST['location_path'])) {
+ set_msg('Location updated successfully.');
+ header('Location: http://'.$_SERVER['HTTP_HOST'].WEBPATH.'/admin/locations.php');
+ exit;
+ } else {
+ set_error('Location update failed.');
+ }
+ } else {
+ $title = 'Edit Location';
+ $nav = INC.'/admin_nav.php';
+ require_once(HEADER);
+ echo '<h2>Edit Location</h2>';
+ $posts = mirror_get_one_location($_POST['location_id']);
+ form_start();
+ include_once(INC.'/forms/location.php');
+ form_hidden('doit','1');
+ form_hidden('action','edit');
+ form_hidden('location_id',$_POST['location_id']);
+ form_submit('submit','','button1','Update');
+ form_end();
+ require_once(FOOTER);
+ exit;
+ }
+ break;
+ case 'delete':
+ if (mirror_delete_location($_POST['location_id'])) {
+ set_msg('Location deleted successfully.');
+ } else {
+ set_error('Location could not be deleted.');
+ }
+ break;
+ }
+ } else {
+ set_error('You must select a mirror to continue.');
+ }
+}
+
+$title = 'Locations';
+$nav = INC.'/admin_nav.php';
+require_once(HEADER);
+echo '<h2>Locations</h2>';
+show_error();
+show_msg();
+
+$locations = mirror_get_locations();
+
+$_GET['sort'] = (!empty($_GET['sort']))?$_GET['sort']:'product_name';
+$_GET['order'] = (!empty($_GET['order']))?$_GET['order']:'ASC';
+$locations = array_order_by($locations,$_GET['sort'],$_GET['order']);
+
+$headers = array(
+ 'location_id'=>'',
+ 'product_name'=>'Product',
+ 'os_name'=>'OS',
+ 'location_path'=>'Path'
+);
+
+$actions = array(
+ 'edit'=>'Edit',
+ 'delete'=>'Delete'
+);
+
+form_start();
+show_list($locations,$headers,'radio',$actions);
+form_end();
+
+echo '<h2>Add a Location</h2>';
+form_start();
+include_once(INC.'/forms/location.php');
+form_submit('add-submit','','button1','Add Location');
+form_end();
+
+require_once(FOOTER);
+?>
diff --git a/php/admin/login.php b/php/admin/login.php
new file mode 100644
index 0000000..5e9d4c3
--- /dev/null
+++ b/php/admin/login.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * Admin login.
+ * @package mirror
+ * @subpackage admin
+ */
+require_once('../cfg/init.php');
+require_once(LIB.'/auth.php');
+
+// authenticate
+if (!empty($_POST['submit'])) {
+ if ($auth = auth_mysql($_POST['username'],$_POST['password'])) {
+ auth_create_session($auth);
+ header('Location: http://'.$_SERVER['HTTP_HOST'].WEBPATH.'/admin/');
+ exit;
+ } else {
+ $msg = 'Authentication failed. Please check username and password and try again.';
+ }
+}
+
+$title='Gentoo Mirror Manager Login';
+$body_tags=' onload="document.getElementById(\'username\').focus();" ';
+require_once(HEADER);
+?>
+<h1>Gentoo Mirror Manager Login</h1>
+<?php echo (!empty($msg))?'<pre>'.$msg.'</pre>':null; ?>
+<form name="form" id="form" method="post" action="./login.php" >
+<div>
+ <label for="username">Username:</label>
+ <input type="text" name="username" id="username" size="30" maxlength="100" />
+</div>
+<br />
+<div>
+ <label for="password">Password:</label>
+ <input type="password" name="password" id="password" size="30" maxlength="100" />
+</div>
+<br />
+<input type="submit" name="submit" id="submit" class="button" value="Log In" />
+</form>
+<?php
+require_once(FOOTER);
+?>
diff --git a/php/admin/logout.php b/php/admin/logout.php
new file mode 100644
index 0000000..d980d9d
--- /dev/null
+++ b/php/admin/logout.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * Admin logout.
+ * @package mirror
+ * @subpackage admin
+ */
+require_once('../cfg/init.php');
+require_once(LIB.'/auth.php');
+auth_logout();
+header('Location: http://'.$_SERVER['HTTP_HOST'].WEBPATH.'/admin/login.php');
+exit;
+?>
diff --git a/php/admin/lstats.php b/php/admin/lstats.php
new file mode 100644
index 0000000..f7f1900
--- /dev/null
+++ b/php/admin/lstats.php
@@ -0,0 +1,59 @@
+<?php
+/**
+ * Location Statistics.
+ * @package mirror
+ * @subpackage admin
+ */
+$protect=1; // protect this page
+require_once('../cfg/init.php');
+
+$stats = db_get("
+ SELECT
+ IF(mirror_location_mirror_map.location_active='0','DISABLED','ok') as location_active,
+ mirror_name,
+ mirror_baseurl,
+ location_path
+ FROM
+ mirror_mirrors,
+ mirror_location_mirror_map,
+ mirror_locations
+ WHERE
+ mirror_mirrors.mirror_id = mirror_location_mirror_map.mirror_id AND
+ mirror_locations.location_id = mirror_location_mirror_map.location_id
+",MYSQL_ASSOC);
+
+$_GET['sort']=(!empty($_GET['sort']))?$_GET['sort']:'location_active';
+$_GET['order']=(!empty($_GET['order']))?$_GET['order']:'ASC';
+$stats=array_order_by($stats,$_GET['sort'],$_GET['order']);
+
+$headers = array(
+ 'location_active'=>'Status',
+ 'mirror_name'=>'Host Name',
+ 'mirror_baseurl'=>'Address',
+ 'location_path'=>'Path'
+);
+
+// should we export to csv?
+if (!empty($_GET['csv'])) {
+ $csv = array();
+ $csv[] = $headers;
+ foreach ($stats as $row) {
+ $csv[] = $row;
+ }
+ csv_send_csv($csv);
+ exit;
+}
+
+$title = 'Location Statistics';
+$nav = INC.'/admin_nav.php';
+require_once(HEADER);
+echo '<h2>Location Statistics</h2>';
+
+echo '<p>This shows whether or not a server is serving up a certain file.</p>';
+
+show_list($stats,$headers,'simple');
+
+echo '<p><a href="./lstats.php?csv=1&amp;sort='.$_GET['sort'].'&amp;order='.$_GET['order'].'">Save this page as CSV &raquo;</a></p>';
+
+require_once(FOOTER);
+?>
diff --git a/php/admin/mirror-list.php b/php/admin/mirror-list.php
new file mode 100644
index 0000000..c161efd
--- /dev/null
+++ b/php/admin/mirror-list.php
@@ -0,0 +1,74 @@
+<?php
+/**
+ * Regions.
+ * @package mirror
+ * @subpackage admin
+ */
+$protect=1; // protect this page
+require_once('../cfg/init.php');
+
+if (!empty($_GET['os'])&&!empty($_GET['product'])) {
+ // clean in os and product strings
+ $os_name = mysql_real_escape_string(trim(strtolower($_GET['os'])));
+ $product_name = mysql_real_escape_string(trim(strtolower($_GET['product'])));
+ // get os and product IDs
+ $os_id = db_name_to_id('mirror_os','os_id','os_name',$os_name);
+ $product_id = db_name_to_id('mirror_products','product_id','product_name',$product_name);
+}
+
+if (!empty($_GET['os_id'])&&!empty($_GET['product_id'])) {
+
+ $os_id = intval($_GET['os_id']);
+ $product_id = intval($_GET['product_id']);
+
+
+ $mirrors = db_get("
+ SELECT DISTINCT
+ mirror_baseurl
+ FROM
+ mirror_mirrors
+ INNER JOIN
+ mirror_location_mirror_map
+ ON
+ mirror_location_mirror_map.mirror_id = mirror_mirrors.mirror_id
+ INNER JOIN
+ mirror_locations
+ ON
+ mirror_location_mirror_map.location_id = mirror_locations.location_id
+ WHERE
+ mirror_locations.os_id = {$os_id} AND
+ mirror_locations.product_id = {$product_id} AND
+ mirror_location_mirror_map.location_active = '1' AND
+ mirror_mirrors.mirror_active = '1'
+ ");
+
+ header("Content-type: text/plain;");
+ foreach ($mirrors as $mirror) {
+ echo $mirror['mirror_baseurl']."\n";
+ }
+ exit;
+
+} else {
+
+ $title = 'Mirror Listing';
+ require_once(HEADER);
+ echo '<h1>Mirror List</h1>';
+ echo '<p>Use this form to get a list of all mirrors serving up active files
+ for the selected Product/OS.</p>';
+ form_start('list','list','get','./mirror-list.php');
+ echo '<div>';
+ form_label('Product', 'product','label-small');
+ form_select('product_id','product','',mirror_get_products_select(),$posts['product_id']);
+ echo ' [<a href="./products.php">edit products</a>]';
+ echo '</div><br />';
+
+ echo '<div>';
+ form_label('OS', 'os','label-small');
+ form_select('os_id','os','',mirror_get_oss_select(),$posts['os_id']);
+ echo ' [<a href="./os.php">edit operating systems</a>]';
+ echo '</div><br />';
+ form_submit('submit','','button1','Update');
+ form_end();
+ require_once(FOOTER);
+}
+?>
diff --git a/php/admin/mstats.php b/php/admin/mstats.php
new file mode 100644
index 0000000..5778d16
--- /dev/null
+++ b/php/admin/mstats.php
@@ -0,0 +1,32 @@
+<?php
+/**
+ * Mirror Statistics.
+ * @package mirror
+ * @subpackage admin
+ */
+$protect=1; // protect this page
+require_once('../cfg/init.php');
+
+$title = 'Mirror Statistics';
+$nav = INC.'/admin_nav.php';
+require_once(HEADER);
+echo '<h2>Mirror Statistics</h2>';
+
+$stats = mirror_get_mirror_stats();
+
+$_GET['sort']=(!empty($_GET['sort']))?$_GET['sort']:'count';
+$_GET['order']=(!empty($_GET['order']))?$_GET['order']:'DESC';
+$stats=array_order_by($stats,$_GET['sort'],$_GET['order']);
+
+$headers = array(
+ 'count'=>'Hits',
+ 'mirror_rating'=>'Rating',
+ 'mirror_name'=>'Host Name',
+ 'mirror_baseurl'=>'Address',
+ 'region_name'=>'Region'
+);
+
+show_list($stats,$headers,'simple');
+
+require_once(FOOTER);
+?>
diff --git a/php/admin/os.php b/php/admin/os.php
new file mode 100644
index 0000000..b150245
--- /dev/null
+++ b/php/admin/os.php
@@ -0,0 +1,100 @@
+<?php
+/**
+ * Operating Systems.
+ * @package mirror
+ * @subpackage admin
+ */
+$protect=1; // protect this page
+require_once('../cfg/init.php');
+
+// add os
+if (!empty($_POST['add-submit'])&&!empty($_POST['os_name'])) {
+ if (mirror_insert_os($_POST['os_name'],$_POST['os_priority'])) {
+ set_msg('OS added successfully.');
+ header('Location: http://'.$_SERVER['HTTP_HOST'].WEBPATH.'/admin/os.php');
+ exit;
+ } else {
+ set_error('OS could not be added because of an unknown error.');
+ }
+}
+
+// process actions
+if (!empty($_POST['submit'])) {
+ if (!empty($_POST['os_id'])) {
+ switch($_POST['action']) {
+ case 'edit':
+ if (!empty($_POST['doit'])) {
+ if (mirror_update_os($_POST['os_id'],$_POST['os_name'],$_POST['os_priority'])) {
+ set_msg('OS updated successfully.');
+ header('Location: http://'.$_SERVER['HTTP_HOST'].WEBPATH.'/admin/os.php');
+ exit;
+ } else {
+ set_error('OS update failed.');
+ }
+ } else {
+ $title = 'Edit OS';
+ $nav = INC.'/admin_nav.php';
+ require_once(HEADER);
+ echo '<h2>Edit OS</h2>';
+ $posts = mirror_get_one_os($_POST['os_id']);
+ form_start();
+ include_once(INC.'/forms/os.php');
+ form_hidden('doit','1');
+ form_hidden('action','edit');
+ form_hidden('os_id',$_POST['os_id']);
+ form_submit('submit','','button1','Update');
+ form_end();
+ require_once(FOOTER);
+ exit;
+ }
+ break;
+ case 'delete':
+ if (!record_exists('mirror_locations','os_id',$_POST['os_id'])&&mirror_delete_os($_POST['os_id'])) {
+ set_msg('OS deleted successfully.');
+ } else {
+ set_error('OS cannot be deleted because it is being used by a file location.');
+ }
+ break;
+ }
+ } else {
+ set_error('You must select a os to continue.');
+ }
+}
+
+$title = 'Operating Systems';
+$nav = INC.'/admin_nav.php';
+require_once(HEADER);
+echo '<h2>Operating Systems</h1>';
+
+show_error();
+show_msg();
+
+$oss = mirror_get_oss();
+
+$_GET['sort']=(!empty($_GET['sort']))?$_GET['sort']:'os_name';
+$_GET['order']=(!empty($_GET['order']))?$_GET['order']:'ASC';
+$oss=array_order_by($oss,$_GET['sort'],$_GET['order']);
+
+$headers = array(
+ 'os_id'=>'',
+ 'os_name'=>'OS Name',
+ 'os_priority'=>'Priority'
+);
+
+$actions = array(
+ 'edit'=>'Edit',
+ 'delete'=>'Delete'
+);
+
+form_start();
+show_list($oss,$headers,'radio',$actions);
+form_end();
+
+echo '<h2>Add a OS</h2>';
+form_start();
+include_once(INC.'/forms/os.php');
+form_submit('add-submit','','button1','Add OS');
+form_end();
+
+require_once(FOOTER);
+?>
diff --git a/php/admin/products.php b/php/admin/products.php
new file mode 100644
index 0000000..e93686f
--- /dev/null
+++ b/php/admin/products.php
@@ -0,0 +1,101 @@
+<?php
+/**
+ * Products.
+ * @package mirror
+ * @subpackage admin
+ */
+$protect=1; // protect this page
+require_once('../cfg/init.php');
+
+// add product
+if (!empty($_POST['add-submit'])&&!empty($_POST['product_name'])) {
+ if (mirror_insert_product($_POST['product_name'],$_POST['product_priority'])) {
+ set_msg('Product added successfully.');
+ header('Location: http://'.$_SERVER['HTTP_HOST'].WEBPATH.'/admin/products.php');
+ exit;
+ } else {
+ set_error('Product could not be added because of an unknown error.');
+ }
+}
+
+// process actions
+if (!empty($_POST['submit'])) {
+ if (!empty($_POST['product_id'])) {
+ switch($_POST['action']) {
+ case 'edit':
+ if (!empty($_POST['doit'])) {
+ if (mirror_update_product($_POST['product_id'],$_POST['product_name'],$_POST['product_priority'])) {
+ set_msg('Product updated successfully.');
+ header('Location: http://'.$_SERVER['HTTP_HOST'].WEBPATH.'/admin/products.php');
+ exit;
+ } else {
+ set_error('Product update failed.');
+ }
+ } else {
+ $title = 'Edit Product';
+ $nav = INC.'/admin_nav.php';
+ require_once(HEADER);
+ echo '<h2>Edit Product</h2>';
+ $posts = mirror_get_one_product($_POST['product_id']);
+ form_start();
+ include_once(INC.'/forms/product.php');
+ form_hidden('doit','1');
+ form_hidden('action','edit');
+ form_hidden('product_id',$_POST['product_id']);
+ form_submit('submit','','button1','Update');
+ form_end();
+ require_once(FOOTER);
+ exit;
+ }
+ break;
+ case 'delete':
+ if (!record_exists('mirror_locations','product_id',$_POST['product_id'])&&mirror_delete_product($_POST['product_id'])) {
+ set_msg('Product deleted successfully.');
+ } else {
+ set_error('Product cannot be deleted because it is being used by a file location.');
+ }
+ break;
+ }
+ } else {
+ set_error('You must select a product to continue.');
+ }
+}
+
+$title = 'Products';
+$nav = INC.'/admin_nav.php';
+require_once(HEADER);
+echo '<h2>Products</h1>';
+
+show_error();
+show_msg();
+
+$products = mirror_get_products();
+
+$_GET['sort']=(!empty($_GET['sort']))?$_GET['sort']:'product_name';
+$_GET['order']=(!empty($_GET['order']))?$_GET['order']:'ASC';
+$products=array_order_by($products,$_GET['sort'],$_GET['order']);
+
+$headers = array(
+ 'product_id'=>'',
+ 'product_name'=>'Product Name',
+ 'product_priority'=>'Priority',
+ 'product_count'=>'Downloads'
+);
+
+$actions = array(
+ 'edit'=>'Edit',
+ 'delete'=>'Delete'
+);
+
+form_start();
+show_list($products,$headers,'radio',$actions);
+form_end();
+
+echo '<h2>Add a Product</h2>';
+form_start();
+include_once(INC.'/forms/product.php');
+form_submit('add-submit','','button1','Add Product');
+form_end();
+
+require_once(FOOTER);
+?>
diff --git a/php/admin/pstats.php b/php/admin/pstats.php
new file mode 100644
index 0000000..e0b4aff
--- /dev/null
+++ b/php/admin/pstats.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * Product Statistics.
+ * @package mirror
+ * @subpackage admin
+ */
+$protect=1; // protect this page
+require_once('../cfg/init.php');
+
+$title = 'Product Statistics';
+$nav = INC.'/admin_nav.php';
+require_once(HEADER);
+echo '<h2>Product Statistics</h2>';
+
+$stats = mirror_get_product_stats();
+
+$_GET['sort']=(!empty($_GET['sort']))?$_GET['sort']:'count';
+$_GET['order']=(!empty($_GET['order']))?$_GET['order']:'DESC';
+$stats=array_order_by($stats,$_GET['sort'],$_GET['order']);
+
+$headers = array(
+ 'count'=>'Hits',
+ 'product_name'=>'Product'
+);
+
+show_list($stats,$headers,'simple');
+
+require_once(FOOTER);
+?>
diff --git a/php/admin/regions.php b/php/admin/regions.php
new file mode 100644
index 0000000..f42c0da
--- /dev/null
+++ b/php/admin/regions.php
@@ -0,0 +1,101 @@
+<?php
+/**
+ * Regions.
+ * @package mirror
+ * @subpackage admin
+ */
+$protect=1; // protect this page
+require_once('../cfg/init.php');
+
+// add region
+if (!empty($_POST['add-submit'])&&!empty($_POST['region_name'])) {
+ if (mirror_insert_region($_POST['region_name'],$_POST['region_priority'])) {
+ set_msg('Region added successfully.');
+ header('Location: http://'.$_SERVER['HTTP_HOST'].WEBPATH.'/admin/regions.php');
+ exit;
+ } else {
+ set_error('Region could not be added because of an unknown error.');
+ }
+}
+
+// process actions
+if (!empty($_POST['submit'])) {
+ if (!empty($_POST['region_id'])) {
+ switch($_POST['action']) {
+ case 'edit':
+ if (!empty($_POST['doit'])) {
+ if (mirror_update_region($_POST['region_id'],$_POST['region_name'],$_POST['region_priority'])) {
+ set_msg('Region updated successfully.');
+ header('Location: http://'.$_SERVER['HTTP_HOST'].WEBPATH.'/admin/regions.php');
+ exit;
+ } else {
+ set_error('Region update failed.');
+ }
+ } else {
+ $title = 'Edit Region';
+ $nav = INC.'/admin_nav.php';
+ require_once(HEADER);
+ echo '<h2>Edit Region</h2>';
+ $posts = mirror_get_one_region($_POST['region_id']);
+ form_start();
+ include_once(INC.'/forms/region.php');
+ form_hidden('doit','1');
+ form_hidden('action','edit');
+ form_hidden('region_id',$_POST['region_id']);
+ form_submit('submit','','button1','Update');
+ form_end();
+ require_once(FOOTER);
+ exit;
+ }
+ break;
+ case 'delete':
+ if (!record_exists('mirror_mirror_region_map','region_id',$_POST['region_id'])&&mirror_delete_region($_POST['region_id'])) {
+ set_msg('Region deleted successfully.');
+ } else {
+ set_error('Region cannot be deleted because it is linked to a mirror.');
+ }
+ break;
+ }
+ } else {
+ set_error('You must select a region to continue.');
+ }
+}
+
+$title = 'Regions';
+$nav = INC.'/admin_nav.php';
+require_once(HEADER);
+echo '<h2>Regions</h2>';
+
+show_error();
+show_msg();
+
+$regions = mirror_get_regions();
+
+$_GET['sort']=(!empty($_GET['sort']))?$_GET['sort']:'region_name';
+$_GET['order']=(!empty($_GET['order']))?$_GET['order']:'ASC';
+$regions=array_order_by($regions,$_GET['sort'],$_GET['order']);
+
+$headers = array(
+ 'region_id'=>'',
+ 'region_name'=>'Region Name',
+ 'mirrors'=>'Mirrors',
+ 'region_priority'=>'Priority'
+);
+
+$actions = array(
+ 'edit'=>'Edit',
+ 'delete'=>'Delete'
+);
+
+form_start();
+show_list($regions,$headers,'radio',$actions);
+form_end();
+
+echo '<h2>Add a Region</h2>';
+form_start();
+include_once(INC.'/forms/region.php');
+form_submit('add-submit','','button1','Add Region');
+form_end();
+
+require_once(FOOTER);
+?>
diff --git a/php/admin/users.php b/php/admin/users.php
new file mode 100644
index 0000000..3017c49
--- /dev/null
+++ b/php/admin/users.php
@@ -0,0 +1,104 @@
+<?php
+/**
+ * Users.
+ * @package mirror
+ * @subpackage admin
+ */
+$protect=1; // protect this page
+require_once('../cfg/init.php');
+
+// add user
+if (!empty($_POST['add-submit'])&&!empty($_POST['username'])&&!empty($_POST['password'])&&!empty($_POST['rpassword'])) {
+ if (mirror_insert_user($_POST['username'],$_POST['password'],$_POST['rpassword'],$_POST['user_firstname'],$_POST['user_lastname'],$_POST['user_email'])) {
+ set_msg('User added successfully.');
+ header('Location: http://'.$_SERVER['HTTP_HOST'].WEBPATH.'/admin/users.php');
+ exit;
+ } else {
+ set_error('User could not be added because of an unknown error.');
+ }
+}
+
+// process actions
+if (!empty($_POST['submit'])) {
+ if (!empty($_POST['user_id'])) {
+ switch($_POST['action']) {
+ case 'edit':
+ if (!empty($_POST['doit'])) {
+ if (mirror_update_user($_POST['user_id'],$_POST['username'],$_POST['password'],$_POST['rpassword'],$_POST['user_firstname'],$_POST['user_lastname'],$_POST['user_email'])) {
+ set_msg('User updated successfully.');
+ header('Location: http://'.$_SERVER['HTTP_HOST'].WEBPATH.'/admin/users.php');
+ exit;
+ } else {
+ set_error('User update failed.');
+ }
+ } else {
+ $title = 'Edit User';
+ $nav = INC.'/admin_nav.php';
+ require_once(HEADER);
+ echo '<h2>Edit User</h2>';
+ $posts = mirror_get_one_user($_POST['user_id']);
+ form_start();
+ include_once(INC.'/forms/user.php');
+ form_hidden('doit','1');
+ form_hidden('action','edit');
+ form_hidden('user_id',$_POST['user_id']);
+ form_submit('submit','','button1','Update');
+ form_end();
+ require_once(FOOTER);
+ exit;
+ }
+ break;
+ case 'delete':
+ if ($_POST['user_id']==$_SESSION['user']['user_id']) {
+ set_error('You cannot delete yourself.');
+ } elseif (mirror_delete_user($_POST['user_id'])) {
+ set_msg('User deleted successfully.');
+ } else {
+ set_error('User could not be deleted because of an error.');
+ }
+ break;
+ }
+ } else {
+ set_error('You must select a user to continue.');
+ }
+}
+
+$title = 'Users';
+$nav = INC.'/admin_nav.php';
+require_once(HEADER);
+echo '<h2>Users</h2>';
+
+show_error();
+show_msg();
+
+$users = mirror_get_users();
+
+$_GET['sort'] = (!empty($_GET['sort']))?$_GET['sort']:'user_lastname';
+$_GET['order'] = (!empty($_GET['order']))?$_GET['order']:'ASC';
+$users = array_order_by($users,$_GET['sort'],$_GET['order']);
+
+$headers = array(
+ 'user_id'=>'',
+ 'user_lastname'=>'Last',
+ 'user_firstname'=>'First',
+ 'user_email'=>'Email',
+ 'username'=>'Username'
+);
+
+$actions = array(
+ 'edit'=>'Edit',
+ 'delete'=>'Delete'
+);
+
+form_start();
+show_list($users,$headers,'radio',$actions);
+form_end();
+
+echo '<h2>Add a User</h2>';
+form_start();
+include_once(INC.'/forms/user.php');
+form_submit('add-submit','','button1','Add User');
+form_end();
+
+require_once(FOOTER);
+?>
diff --git a/php/cfg/admin_init.php b/php/cfg/admin_init.php
new file mode 100644
index 0000000..7d22ab3
--- /dev/null
+++ b/php/cfg/admin_init.php
@@ -0,0 +1,15 @@
+<?php
+/**
+ * Admin initialization.
+ * @package mirror
+ * @subpackage cfg
+ */
+require_once(LIB.'/auth.php'); // auth functions
+require_once(LIB.'/forms.php'); // form library
+require_once(LIB.'/list.php'); // list library
+
+if (!auth_is_valid_session()) {
+ header('Location: http://'.$_SERVER['HTTP_HOST'].WEBPATH.'/admin/login.php');
+ exit;
+}
+?>
diff --git a/php/cfg/config-dist.php b/php/cfg/config-dist.php
new file mode 100644
index 0000000..308e844
--- /dev/null
+++ b/php/cfg/config-dist.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * Mirror configuration document.
+ * @package mirror
+ * @subpackage cfg
+ */
+define('FILEPATH','/var/www/download'); // filepath of root dir
+define('WEBPATH',''); // web path of root dir
+define('LIB',FILEPATH.'/lib'); // path to lib dir
+define('INC',FILEPATH.'/inc'); // path to inc dir
+define('HEADER',INC.'/header.php'); // header document
+define('FOOTER',INC.'/footer.php'); // footer document
+define('DBHOST', ''); // db host
+define('DBNAME', ''); // db name
+define('DBUSER', ''); // db user
+define('DBPASS', ''); // db pass
+define('LOGGING',1); // enable logging? 1=on 0=off
+?>
diff --git a/php/cfg/init.php b/php/cfg/init.php
new file mode 100644
index 0000000..4eb6ed0
--- /dev/null
+++ b/php/cfg/init.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * Init.
+ * @package mirror
+ * @subpackage cfg
+ */
+require_once('config.php'); // config file that defines constants
+require_once(LIB.'/util.php'); // util file for random functions (no SQL here)
+require_once(LIB.'/csv.php'); // util file for random functions (no SQL here)
+$start = microtime_float(); // start timer
+require_once(LIB.'/mirror.php'); // user and admin functions for the mirror app (some SQL)
+require_once(LIB.'/db.php'); // core mysql wrappers used in mirror functions
+db_connect(DBHOST,DBUSER,DBPASS); // open persistent connection to db
+db_select(DBNAME); // select db
+if (!empty($protect)) {
+ require_once('admin_init.php');
+}
+?>
diff --git a/php/css/print.css b/php/css/print.css
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/php/css/print.css
diff --git a/php/css/screen.css b/php/css/screen.css
new file mode 100644
index 0000000..e2e67c9
--- /dev/null
+++ b/php/css/screen.css
@@ -0,0 +1,84 @@
+/* nav */
+ul#nav li a {
+ font-weight:bold;
+}
+ul#nav li ul li a {
+ font-weight:normal;
+}
+.logout {
+ color:#f00;
+}
+
+/* forms */
+.label-small {
+ display: inline;
+ float: left;
+ width: 8em;
+ padding-right: 1ex;
+ text-align:right;
+}
+.label-medium{
+ display: inline;
+ float: left;
+ width: 14em;
+ padding-right: 1ex;
+ text-align:right;
+}
+.label-large{
+ display: inline;
+ float: left;
+ width: 20em;
+ padding-right: 1ex;
+ text-align:right;
+}
+.button1 {
+ background-color:#9c9;
+ cursor:pointer;
+}
+.button1:hover {
+ background-color:#fff;
+ border:inset 2px #999;
+}
+
+/* lists */
+.list {
+ margin-top:.5em;
+}
+.list td {
+ padding:.2em;
+ text-align:left;
+}
+.list td label {
+ border-bottom:1px dashed #999;
+ font-weight:normal;
+}
+.list th {
+ background:#eee;
+ border:1px solid #000;
+ font-weight:bold;
+ padding:0;
+}
+.list th a {
+ display:block;
+ padding:.2em 1.2em .2em .2em;
+ text-align:left;
+}
+.list th a:hover {
+ background-color:#fff;
+}
+.row1 {
+ background:#ddd;
+}
+.row2 {
+ background:#ccc;
+}
+.row1:hover, .row2:hover {
+ background-color:#fff;
+}
+.sort-desc {
+ background:#ccf url(../img/up.gif) no-repeat right;
+}
+.sort-asc {
+ background:#ccf url(../img/down.gif) no-repeat right;
+}
+
diff --git a/php/images/gridtest.gif b/php/images/gridtest.gif
new file mode 100644
index 0000000..6dd05dc
--- /dev/null
+++ b/php/images/gridtest.gif
Binary files differ
diff --git a/php/images/gtop-www.jpg b/php/images/gtop-www.jpg
new file mode 100644
index 0000000..4122618
--- /dev/null
+++ b/php/images/gtop-www.jpg
Binary files differ
diff --git a/php/img/down.gif b/php/img/down.gif
new file mode 100644
index 0000000..2813965
--- /dev/null
+++ b/php/img/down.gif
Binary files differ
diff --git a/php/img/up.gif b/php/img/up.gif
new file mode 100644
index 0000000..6d5a795
--- /dev/null
+++ b/php/img/up.gif
Binary files differ
diff --git a/php/inc/admin_nav.php b/php/inc/admin_nav.php
new file mode 100644
index 0000000..073ab0a
--- /dev/null
+++ b/php/inc/admin_nav.php
@@ -0,0 +1,27 @@
+<?php
+/**
+ * Admin navigation.
+ * @package mirror
+ * @subpackage inc
+ */
+?>
+<div id="side">
+<ul id="nav">
+<li><a href="<?php echo WEBPATH; ?>/admin/logout.php" class="logout" title="Logout to end your session.">&laquo; Logout <?php echo $_SESSION['user']['username']?></a></li>
+<li>
+ <a href="<?php echo WEBPATH; ?>/admin/" title="Manage current mirrors.">Mirrors</a>
+ <ul>
+ <li><a href="<?php echo WEBPATH; ?>/admin/regions.php" title="A region is an area that has a set of mirrors.">Regions</a></li>
+ </ul>
+</li>
+<li>
+ <a href="<?php echo WEBPATH; ?>/admin/products.php" title="Products (firefox, thunderbird, etc.)">Products</a>
+ <ul>
+ <li><a href="<?php echo WEBPATH; ?>/admin/locations.php" title="Product file locations based on OS.">File Locations</a></li>
+ <li><a href="<?php echo WEBPATH; ?>/admin/os.php" title="Operating systems.">Operating Systems</a></li>
+ <li><a href="<?php echo WEBPATH; ?>/admin/lstats.php" title="View location statuses.">Location Statuses</a></li>
+ </ul>
+</li>
+<li><a href="<?php echo WEBPATH; ?>/admin/users.php" title="Manage administrator accounts.">Users</a></li>
+</ul>
+</div>
diff --git a/php/inc/footer.php b/php/inc/footer.php
new file mode 100644
index 0000000..efa17e7
--- /dev/null
+++ b/php/inc/footer.php
@@ -0,0 +1,24 @@
+<?php
+/**
+ * Footer document.
+ * @package mirror
+ * @subpackage inc
+ */
+?>
+</td></tr></table></td></tr></table>
+<hr class="hide">
+</div>
+<?php
+if (!empty($nav)) {
+ echo '</div>';
+}
+?>
+<div id="footer">
+<p class="copyright">Copyright &copy; 2005 The Gentoo Foundation, portions Copyright &copy; 1998-2004 The Mozilla Organization</p>
+</div>
+</div>
+</body>
+</html>
+<?php
+ob_end_flush();
+?>
diff --git a/php/inc/forms/location.php b/php/inc/forms/location.php
new file mode 100644
index 0000000..60e35cb
--- /dev/null
+++ b/php/inc/forms/location.php
@@ -0,0 +1,23 @@
+<?php
+/**
+ * File location form.
+ * @package mirror
+ * @subpackage forms
+ */
+echo '<div>';
+form_label('Product', 'product','label-small');
+form_select('product_id','product','',mirror_get_products_select(),$posts['product_id']);
+echo ' [<a href="./products.php">edit products</a>]';
+echo '</div><br />';
+
+echo '<div>';
+form_label('OS', 'os','label-small');
+form_select('os_id','os','',mirror_get_oss_select(),$posts['os_id']);
+echo ' [<a href="./os.php">edit operating systems</a>]';
+echo '</div><br />';
+
+echo '<div>';
+form_label('File Location', 'floc','label-small');
+form_text('location_path', 'floc', '', $posts['location_path'], 30, 100);
+echo '</div><br />';
+?>
diff --git a/php/inc/forms/mirror.php b/php/inc/forms/mirror.php
new file mode 100644
index 0000000..c1e7dcb
--- /dev/null
+++ b/php/inc/forms/mirror.php
@@ -0,0 +1,27 @@
+<?php
+/**
+ * Region form.
+ * @package mirror
+ * @subpackage forms
+ */
+echo '<div>';
+form_label('Mirror Name', 'mname','label-small');
+form_text('mirror_name', 'mname', '', $posts['mirror_name'], 30, 100);
+echo '</div><br />';
+
+echo '<div>';
+form_label('Region', 'mregion','label-small');
+form_select('region_id','mregion','',mirror_get_regions_select(),$posts['region_id']);
+echo ' [<a href="./regions.php">edit regions</a>]';
+echo '</div><br />';
+
+echo '<div>';
+form_label('Base URL', 'murl','label-small');
+form_text('mirror_baseurl', 'murl', '', $posts['mirror_baseurl'], 30, 100);
+echo '</div><br />';
+
+echo '<div>';
+form_label('Rating', 'mrating','label-small');
+form_text('mirror_rating', 'mrating', '', $posts['mirror_rating'], 30, 100);
+echo '</div><br />';
+?>
diff --git a/php/inc/forms/os.php b/php/inc/forms/os.php
new file mode 100644
index 0000000..63a7643
--- /dev/null
+++ b/php/inc/forms/os.php
@@ -0,0 +1,16 @@
+<?php
+/**
+ * OS form.
+ * @package mirror
+ * @subpackage forms
+ */
+echo '<div>';
+form_label('OS Name', 'oname','label-small');
+form_text('os_name', 'oname', '', $posts['os_name'], 30, 100);
+echo '</div><br />';
+
+echo '<div>';
+form_label('Priority', 'p','label-small');
+form_text('os_priority', 'p', '', $posts['os_priority'], 30, 100);
+echo '</div><br />';
+?>
diff --git a/php/inc/forms/product.php b/php/inc/forms/product.php
new file mode 100644
index 0000000..0dc3c04
--- /dev/null
+++ b/php/inc/forms/product.php
@@ -0,0 +1,16 @@
+<?php
+/**
+ * Product form.
+ * @package mirror
+ * @subpackage forms
+ */
+echo '<div>';
+form_label('Product Name', 'pname','label-small');
+form_text('product_name', 'pname', '', $posts['product_name'], 30, 100);
+echo '</div><br />';
+
+echo '<div>';
+form_label('Priority', 'pty','label-small');
+form_text('product_priority', 'pty', '', $posts['product_priority'], 30, 100);
+echo '</div><br />';
+?>
diff --git a/php/inc/forms/region.php b/php/inc/forms/region.php
new file mode 100644
index 0000000..9262809
--- /dev/null
+++ b/php/inc/forms/region.php
@@ -0,0 +1,16 @@
+<?php
+/**
+ * Region form.
+ * @package mirror
+ * @subpackage forms
+ */
+echo '<div>';
+form_label('Region Name', 'rname','label-small');
+form_text('region_name', 'rname', '', $posts['region_name'], 30, 100);
+echo '</div><br />';
+
+echo '<div>';
+form_label('Priority', 'rp','label-small');
+form_text('region_priority', 'rp', '', $posts['region_priority'], 30, 100);
+echo '</div><br />';
+?>
diff --git a/php/inc/forms/user.php b/php/inc/forms/user.php
new file mode 100644
index 0000000..bfd92bc
--- /dev/null
+++ b/php/inc/forms/user.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * User form.
+ * @package mirror
+ * @subpackage forms
+ */
+echo '<div>';
+form_label('Username', 'uname','label-small');
+form_text('username', 'uname', '', $posts['username'], 30, 100);
+echo '</div><br />';
+
+echo '<div>';
+form_label('Password', 'password','label-small');
+form_password('password', 'password', '', 30, 100);
+echo '</div><br />';
+
+echo '<div>';
+form_label('Re-enter Password', 'rpassword','label-small');
+form_password('rpassword', 'rpassword', '', 30, 100);
+echo '</div><br />';
+
+echo '<div>';
+form_label('First Name', 'fname','label-small');
+form_text('user_firstname', 'fname', '', $posts['user_firstname'], 30, 100);
+echo '</div><br />';
+
+echo '<div>';
+form_label('Last Name', 'lname','label-small');
+form_text('user_lastname', 'lname', '', $posts['user_lastname'], 30, 100);
+echo '</div><br />';
+
+echo '<div>';
+form_label('Email', 'email','label-small');
+form_text('user_email', 'email', '', $posts['user_email'], 30, 100);
+echo '</div><br />';
+
+?>
diff --git a/php/inc/header.php b/php/inc/header.php
new file mode 100644
index 0000000..dbe97b2
--- /dev/null
+++ b/php/inc/header.php
@@ -0,0 +1,55 @@
+<?php
+/**
+ * Header document.
+ * @package mirror
+ * @subpackage inc
+ */
+ob_start();
+?>
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+<link rel="home" title="Home" href="http://www.gentoo.org/">
+<link rel="stylesheet" type="text/css" href="http://www.gentoo.org/css/main.css" media="all">
+<link rel="stylesheet" type="text/css" href="<?php echo WEBPATH; ?>/css/screen.css" media="screen">
+
+<link rel="icon" href="http://www.gentoo.org/favicon.ico" type="image/png">
+<title><?php echo $title; ?></title>
+<meta name="robots" content="all">
+<meta name="keywords" content="gentoo linux distribution source compile">
+<?php echo (!empty($extra_headers))?$extra_headers:null?>
+</head>
+<body id="www-mozilla-org" class="secondLevel"<?php echo (!empty($body_tags))?' '.$body_tags.' ':null; ?>>
+<div id="container">
+<div id="header">
+
+<table border="0" width="100%" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="top" height="125" width="1%" bgcolor="#45347b"><a href="/"><img border="0" src="/images/gtop-www.jpg" alt="Gentoo Logo"></a></td>
+<td valign="bottom" align="left" bgcolor="#000000" colspan="2"><p class="menu">
+ <H2><font color="#FFFFFF">&nbsp;&nbsp; Gentoo Mirror Management</font></H2>
+ </p></td>
+</tr>
+<tr>
+<td valign="top" align="right" width="1%" bgcolor="#dddaec"><table width="100%" cellspacing="0" cellpadding="0" border="0">
+<tr><td height="1%" valign="top" align="right"><img src="/images/gridtest.gif" alt="Gentoo Spaceship"></td></tr>
+<tr><td height="99%" valign="top" align="right"><table cellspacing="0" cellpadding="5" border="0"><tr><td valign="top">
+<p class="altmenu">
+<?php
+if (!empty($nav)) {
+ require_once($nav);
+}
+?>
+</p>
+
+<br><br>
+</td></tr></table></td></tr></table>
+</td><td><table><tr><td>&nbsp;&nbsp;</td><td>
+
+</div>
+<div id="mBody">
+<?php
+ echo '<div id="mainContent">';
+?>
+
diff --git a/php/inc/nav.php b/php/inc/nav.php
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/php/inc/nav.php
diff --git a/php/index-list.php b/php/index-list.php
new file mode 100644
index 0000000..1705ee6
--- /dev/null
+++ b/php/index-list.php
@@ -0,0 +1,83 @@
+<?php
+/**
+ * Regions.
+ * @package mirror
+ * @subpackage admin
+ */
+require_once('./cfg/init.php');
+require_once(LIB.'/auth.php'); // auth functions
+require_once(LIB.'/forms.php'); // form library
+require_once(LIB.'/list.php'); // list library
+error_reporting(E_GET);
+
+if (!empty($_GET['os'])&&!empty($_GET['product'])) {
+ // clean in os and product strings
+ $os_name = mysql_real_escape_string(trim(strtolower($_GET['os'])));
+ $product_name = mysql_real_escape_string(trim(strtolower($_GET['product'])));
+ // get os and product IDs
+ $os_id = db_name_to_id('mirror_os','os_id','os_name',$os_name);
+ $product_id = db_name_to_id('mirror_products','product_id','product_name',$product_name);
+}
+if (!empty($_GET['os_id'])&&!empty($_GET['product_id'])) {
+ $os_id = intval($_GET['os_id']);
+ $product_id = intval($_GET['product_id']);
+}
+
+if (!empty($os_id)&&!empty($product_id)) {
+
+ $mirrors = db_get("
+ SELECT DISTINCT
+ mirror_baseurl, location_path
+ FROM
+ mirror_mirrors
+ INNER JOIN
+ mirror_location_mirror_map
+ ON
+ mirror_location_mirror_map.mirror_id = mirror_mirrors.mirror_id
+ INNER JOIN
+ mirror_locations
+ ON
+ mirror_location_mirror_map.location_id = mirror_locations.location_id
+ WHERE
+ mirror_locations.os_id = {$os_id} AND
+ mirror_locations.product_id = {$product_id} AND
+ mirror_location_mirror_map.location_active = '1' AND
+ mirror_mirrors.mirror_active = '1'
+ ORDER BY
+ mirror_rating DESC, mirror_baseurl
+ ");
+
+ header("Content-type: text/plain;");
+ foreach ($mirrors as $mirror) {
+ $b = $mirror['mirror_baseurl'];
+ $l = $mirror['location_path'];
+ if($l[0] == '/' && substr($b,-1) == '/') {
+ $b = substr($b, 0, -1);
+ }
+ echo $b.$l."\n";
+ }
+ exit;
+
+} else {
+
+ $title = 'Mirror Listing';
+ require_once(HEADER);
+ echo '<h1>Mirror List</h1>';
+ echo '<p>Use this form to get a list of all mirrors serving up active files
+ for the selected Product/OS.</p>';
+ form_start('list','list','get','./index-list.php');
+ echo '<div>';
+ form_label('Product', 'product','label-small');
+ form_select('product_id','product','',mirror_get_products_select(),$_GET['product_id']);
+ echo ' [<a href="./products.php">edit products</a>]';
+ echo '</div><br />';
+
+ echo '<div>';
+ form_label('OS', 'os','label-small');
+ form_select('os_id','os','',mirror_get_oss_select(),$_GET['os_id']);
+ echo ' [<a href="./os.php">edit operating systems</a>]';
+ echo '</div><br />';
+ form_submit('submit','','button1','Update');
+ form_end();
+ require_once(FOOTER);
+}
diff --git a/php/index.php b/php/index.php
new file mode 100644
index 0000000..eacb99e
--- /dev/null
+++ b/php/index.php
@@ -0,0 +1,75 @@
+<?php
+/**
+ * Main handler.
+ * @package mirror
+ * @subpackage pub
+ */
+error_reporting(0); // hide all errors
+require_once('./cfg/config.php'); // config file that defines constants
+
+// if we don't have an os, make it windows, playing the odds
+if (empty($_GET['os'])) {
+ $_GET['os'] = 'Any';
+}
+
+// do we even have an os or product?
+if (!empty($_GET['os'])&&!empty($_GET['product'])) {
+ require_once(LIB.'/db.php'); // core mysql wrappers
+ db_connect(DBHOST,DBUSER,DBPASS); // open persistent connection to db
+ db_select(DBNAME); // select db
+
+ // clean in os and product strings
+ $os_name = mysql_real_escape_string(trim(strtolower($_GET['os'])));
+ $product_name = mysql_real_escape_string(trim(strtolower($_GET['product'])));
+
+ // get os and product IDs
+ $os_id = db_name_to_id('mirror_os','os_id','os_name',$os_name);
+ $product_id = db_name_to_id('mirror_products','product_id','product_name',$product_name);
+
+ // do we have a valid os and product?
+ if (!empty($os_id)&&!empty($product_id)) {
+ $location = db_get_one("SELECT location_id,location_path FROM mirror_locations WHERE product_id={$product_id} AND os_id={$os_id}");
+
+ // did we get a valid location?
+ if (!empty($location)) {
+ $mirror = db_get_one("SELECT mirror_mirrors.mirror_id,mirror_baseurl FROM mirror_mirrors, mirror_location_mirror_map WHERE mirror_mirrors.mirror_id = mirror_location_mirror_map.mirror_id AND mirror_location_mirror_map.location_id = {$location['location_id']} AND mirror_active='1' AND location_active ='1' ORDER BY rand()*(1/mirror_rating)");
+
+ // did we get a valid mirror?
+ if (!empty($mirror)) {
+
+ // if logging is enabled, insert log
+ if (LOGGING) {
+ db_query("UPDATE mirror_mirrors SET mirror_count=mirror_count+1 WHERE mirror_id={$mirror['mirror_id']}");
+ db_query("UPDATE mirror_products SET product_count=product_count+1 WHERE product_id={$product_id}");
+ }
+
+ // LANGUAGE HACK
+ if (!empty($_GET['lang'])) {
+//// $location['location_path'] = str_replace('x86',$_GET['lang'],$location['location_path']);
+ $location['location_path'] = str_replace('en-US',$_GET['lang'],$location['location_path']);
+ }
+
+ // BitTorrent HACK - robbat2
+ if (!empty($_GET['extra'])) {
+ $extra = $_GET['extra'];
+ $location['location_path'] .= ereg_replace('\?.*|&.*','',$extra);
+ }
+
+ // if we are just testing, then just print and exit.
+ if (!empty($_GET['print'])) {
+ print('Location: '.$mirror['mirror_baseurl'].$location['location_path']);
+ exit;
+ }
+
+ // otherwise, by default, redirect them and exit
+ header('Location: '.$mirror['mirror_baseurl'].$location['location_path']);
+ exit;
+ }
+ }
+ }
+}
+
+// if we get here, the request was invalid; redirect to mozilla home
+header('Location: http://www.gentoo.org/');
+exit;
+?>
diff --git a/php/index.php.orig b/php/index.php.orig
new file mode 100644
index 0000000..9cc7791
--- /dev/null
+++ b/php/index.php.orig
@@ -0,0 +1,79 @@
+<?php
+/**
+ * Main handler.
+ * @package mirror
+ * @subpackage pub
+ */
+error_reporting(0); // hide all errors
+require_once('./cfg/config.php'); // config file that defines constants
+
+// if we don't have an os, make it windows, playing the odds
+if (empty($_GET['os'])) {
+ $_GET['os'] = 'Any';
+}
+
+// do we even have an os or product?
+if (!empty($_GET['os'])&&!empty($_GET['product'])) {
+ require_once(LIB.'/db.php'); // core mysql wrappers
+ db_connect(DBHOST,DBUSER,DBPASS); // open persistent connection to db
+ db_select(DBNAME); // select db
+
+ // clean in os and product strings
+ $os_name = mysql_real_escape_string(trim(strtolower($_GET['os'])));
+ $product_name = mysql_real_escape_string(trim(strtolower($_GET['product'])));
+
+ printf("osname=%s<br />\nprname=%s<br />\n",$os_name,$product_name);
+
+ // get os and product IDs
+ $os_id = db_name_to_id('mirror_os','os_id','os_name',$os_name);
+ $product_id = db_name_to_id('mirror_products','product_id','product_name',$product_name);
+
+ printf("osid=%s<br />\nprid=%s<br />\n",$os_id,$product_id);
+
+ // do we have a valid os and product?
+ if (!empty($os_id)&&!empty($product_id)) {
+ $location = db_get_one("SELECT location_id,location_path FROM mirror_locations WHERE product_id={$product_id} AND os_id={$os_id}");
+
+ // did we get a valid location?
+ if (!empty($location)) {
+ $mirror = db_get_one("SELECT mirror_mirrors.mirror_id,mirror_baseurl FROM mirror_mirrors, mirror_location_mirror_map WHERE mirror_mirrors.mirror_id = mirror_location_mirror_map.mirror_id AND mirror_location_mirror_map.location_id = {$location['location_id']} AND mirror_active='1' AND location_active ='1' ORDER BY rand()*(1/mirror_rating)");
+
+ // did we get a valid mirror?
+ if (!empty($mirror)) {
+
+ // if logging is enabled, insert log
+ if (LOGGING) {
+ db_query("UPDATE mirror_mirrors SET mirror_count=mirror_count+1 WHERE mirror_id={$mirror['mirror_id']}");
+ db_query("UPDATE mirror_products SET product_count=product_count+1 WHERE product_id={$product_id}");
+ }
+
+ // LANGUAGE HACK
+ if (!empty($_GET['lang'])) {
+//// $location['location_path'] = str_replace('x86',$_GET['lang'],$location['location_path']);
+ $location['location_path'] = str_replace('en-US',$_GET['lang'],$location['location_path']);
+ }
+
+ // BitTorrent HACK - robbat2
+ if (!empty($_GET['extra'])) {
+ $extra = $_GET['extra'];
+ $location['location_path'] .= ereg_replace('\?.*|&.*','',$extra);
+ }
+
+ // if we are just testing, then just print and exit.
+ if (!empty($_GET['print'])) {
+ print('Location: '.$mirror['mirror_baseurl'].$location['location_path']);
+ exit;
+ }
+
+ // otherwise, by default, redirect them and exit
+ header('Location: '.$mirror['mirror_baseurl'].$location['location_path']);
+ exit;
+ }
+ }
+ }
+}
+
+// if we get here, the request was invalid; redirect to mozilla home
+header('Location: http://www.gentoo.org/');
+exit;
+?>
diff --git a/php/lib/auth.php b/php/lib/auth.php
new file mode 100644
index 0000000..f03db32
--- /dev/null
+++ b/php/lib/auth.php
@@ -0,0 +1,75 @@
+<?php
+/**
+ * Home-cooked auth libraries - because PEAR is fat.
+ * @package mirror
+ * @subpackage lib
+ * @todo re-enforce one-per-user session limit
+ */
+
+/**
+ * Check admin session against sessions table in database.
+ * @return bool
+ */
+function auth_is_valid_session()
+{
+ if (!empty($_COOKIE['mozilla-mirror-admin'])) { // check cookie
+ $res = db_query("SELECT * FROM mirror_sessions WHERE session_id = '{$_COOKIE['mozilla-mirror-admin']}'"); // check db for id
+ if ($res && db_numrows($res)>0) {
+ $buf = db_fetch($res,MYSQL_ASSOC);
+ // comment line below to disable gc and allow multiple sessions per username
+ db_query("DELETE FROM mirror_sessions WHERE username='{$buf['username']}' AND session_id != '{$_COOKIE['mozilla-mirror-admin']}'"); // garbage collection
+ $user = db_fetch(db_query("SELECT * FROM mirror_users WHERE username='{$buf['username']}'"),MYSQL_ASSOC);
+ if (empty($_SESSION)) {
+ auth_create_session($user); // if session isn't started, create it and push user data
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Authentication a user.
+ * @param string $username
+ * @param string $password
+ * @return array|bool array containing user data or false on failure
+ */
+function auth_mysql($username,$password)
+{
+ if (empty($username)||empty($password)) {
+ return false;
+ }
+ $username = trim(strip_tags(addslashes($username)));
+ $password = trim(strip_tags(addslashes($password)));
+ $res = db_query("SELECT * FROM mirror_users WHERE username='{$username}' AND password=MD5('{$password}')");
+ if ($res && db_numrows($res)>0) {
+ return db_fetch($res,MYSQL_ASSOC);
+ } else {
+ return false;
+ }
+}
+
+/**
+ * Start a valid session.
+ * @param array $user array containing user information.
+ */
+function auth_create_session($user,$secure=0)
+{
+ session_name('mozilla-mirror-admin');
+ session_set_cookie_params(0,'/',$_SERVER['HTTP_HOST'],$secure);
+ session_start();
+ db_query("INSERT INTO mirror_sessions(session_id,username) VALUES('".session_id()."','{$user['username']}')");
+ $_SESSION['user']=$user;
+}
+
+/**
+ * Logout.
+ */
+function auth_logout()
+{
+ // comment line below to keep gc from deleting other sessions for this user
+ db_query("DELETE FROM mirror_sessions WHERE session_id='{$_COOKIE['mozilla-mirror-admin']}' OR username='{$_SESSION['user']['username']}'");
+ $_COOKIE = array();
+ $_SESSION = array();
+}
+?>
diff --git a/php/lib/csv.php b/php/lib/csv.php
new file mode 100644
index 0000000..e98d37c
--- /dev/null
+++ b/php/lib/csv.php
@@ -0,0 +1,216 @@
+<?php
+/**
+ * Functions that take a db result and export it to CSV.
+ * Usage example:
+ * <code>
+ * if ($_GET['csv'])
+ * {
+ * $res=db_query("SELECT * FROM fic_courses");
+ * csv_send_csv($res);
+ * exit;
+ * }
+ * </code>
+ * @package libs
+ * @subpackage csv
+ * @author Richard Faaberg <faabergr@onid.orst.edu>
+ * @author Mike Morgan <mike.morgan@oregonstate.edu>
+ * @copyright Central Web Services, Oregon State University
+ */
+
+/**
+ * @param resource $res MySQL resource / result
+ * @return array $ret_val array of CSV rows, parsed properly (false if $res is not resource)
+ */
+function csv_export_to_csv($res)
+{
+ // parse all results, format for CSV
+ while ( $buf=db_fetch($res,MYSQL_ASSOC) )
+ {
+ // get the keys (headers), if not already done
+ if ( empty($heads) )
+ {
+ $heads=array_keys($buf);
+ foreach ($heads as $key=>$val)
+ {
+ $heads[$key]=csv_add_quotes(csv_fix_quotes($val));
+ }
+ $heads=implode(',',$heads);
+ $csv[]=$heads."\n";
+ }
+ // fix inner quotes, add outer quotes for all values
+ $row=csv_array_to_csv($buf);
+ $csv[]=$row."\n";
+ }
+ return $csv;
+}
+
+/**
+ * Use a resource or two dimensional array, then send the CSV results to user.
+ * @param mixed $res MySQL resource / result, or a two dimensional array
+ * @param string $name name of the export file
+ * @return bool true if file sent, false otherwise
+ */
+function csv_send_csv($res,$name=null)
+{
+ // set name of the export file
+ $filename=(is_null($name))?'export-'.date('Y-m-d').'.csv':$name.'.csv';
+ // check for valid resource
+ if ( is_resource($res) )
+ {
+ $csv=csv_export_to_csv($res);
+ }
+ elseif( is_array($res) && !empty($res) )
+ {
+ foreach ($res as $row)
+ {
+ if ( !is_array($row) )
+ ;
+ else
+ $csv[] = csv_array_to_csv($row)."\n";
+ }
+ }
+
+ if ( is_array($csv) )
+ {
+ // stream csv to user
+ header("Content-type: application/x-csv");
+ header('Content-disposition: inline; filename="'.$filename.'"');
+ header('Cache-Control: private');
+ header('Pragma: public');
+ foreach ($csv as $row)
+ {
+ echo $row;
+ }
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Replace quotes inside of a field with double quotes, which is something CSV requires.
+ * @param string $string unquoted quotes
+ * @return string $string quoted quotes
+ */
+function csv_fix_quotes($string)
+{
+ return preg_replace('/"/','""',$string);
+}
+
+/**
+ * Replace line breaks with commas trailed by a space.
+ * @param string $string string containing line breaks
+ * @param string string without line breaks
+ */
+function csv_fix_line_breaks($string)
+{
+ return preg_replace('/(\n\r|\r)/','\n',$string);
+}
+
+/**
+ * Replaces instances of double quotes in a string with a single quote.
+ * @param string $string the string to perform the replacement on
+ * @return string the string with "" replaced by "
+ */
+function csv_unfix_quotes($string)
+{
+ return preg_replace('/""/', '"', $string);
+}
+
+/**
+ * Place quotes outside of every field, which inherently solves space, line break issues.
+ * @param string $string
+ * @return string $string with quotes around it
+ */
+function csv_add_quotes($string)
+{
+ return '"'.$string.'"';
+}
+
+/**
+ * Removes quotes from the beginning and the end of a string.
+ * @param string $string the string to remove the quotes from
+ * @return string the string, sans quotes at the beginning and end
+ */
+function csv_remove_quotes($string)
+{
+ $pattern = "/^\"(.*)\"$/";
+ $replacement = "$1";
+ return preg_replace($pattern, $replacement, $string);
+}
+
+/**
+ * Convert an array into a CSV string with quotes around each value.
+ * @param array $array
+ * @return string the values in $array surrounded by quotes and separated by commas
+ */
+function csv_array_to_csv($array)
+{
+ $csv_arr = array();
+ foreach ($array as $value)
+ {
+ $csv_arr[]=csv_add_quotes(csv_fix_quotes(csv_fix_line_breaks($value)));
+ }
+ $csv_string=implode(',',$csv_arr);
+
+ return $csv_string;
+}
+
+/**
+ * Convert a CSV string into an array.
+ * Please use sparingly - this creates temp files
+ * @param string $string the CSV string
+ * @return array the elements from the CSV string in an array
+ */
+function csv_csv_to_array($string)
+{
+ $return = array();
+ $length = strlen($string);
+
+ // create a temp file and write the string to it
+ $tmpfname = tempnam('/tmp', 'csvlib');
+ $fh = fopen($tmpfname, 'w');
+ fwrite($fh, $string);
+ fclose($fh);
+
+ // open the file for csv parsing
+ $csvh = fopen($tmpfname, 'r');
+ while (($arraydata = fgetcsv($csvh, $length, ',')) !== false)
+ {
+ $return = array_merge($return, $arraydata);
+ }
+
+ fclose($csvh);
+ unlink($tmpfname);
+
+ return $return;
+}
+
+/**
+ * Read a CSV file into a two dimensional array
+ * It returns all the rows in the file, so if the first row are headers, you'd need to take care of that in the returned array
+ * @param string $filepath the path to the csv file
+ * @param string $delimiter delimiter, default to ','
+ * @param string $enclosure enclosure character, default to '"'
+ * @return &array the two dimensional array with the csv file content, or an empty if an error occured
+ */
+function &csv_csv_file_to_array($filepath, $delimiter=',', $enclosure='"')
+{
+ $return = array();
+
+ if (!file_exists($filepath) || !is_readable($filepath))
+ return $return;
+
+ $fh =& fopen($filepath, 'r');
+ $size = filesize($filepath)+1;
+
+ while ($data =& fgetcsv($fh, $size, $delimiter, $enclosure))
+ {
+ $return[] = $data;
+ }
+
+ fclose($fh);
+
+ return $return;
+}
+?>
diff --git a/php/lib/db.php b/php/lib/db.php
new file mode 100644
index 0000000..3f9435f
--- /dev/null
+++ b/php/lib/db.php
@@ -0,0 +1,298 @@
+<?php
+/**
+ * Minimal wrappers for core PHP mysql_* functions.
+ * @package mirror
+ * @subpackage lib
+ */
+
+/**
+ * Connect to a MySQL database server.
+ * @param string $host db server, defaults to localhost
+ * @param string $user db username
+ * @param string $password db password
+ * @return resource dbh
+ */
+function db_connect($host='localhost',$user=null,$password=null)
+{
+ static $dbh = null;
+ if (!empty($host) && isset($user) && isset($password)) {
+ $dbh = @mysql_connect($host,$user,$password);
+ }
+ if (is_resource($dbh)) {
+ return $dbh;
+ }
+ else die("Unable to create database connection in db_connect()");
+}
+
+/**
+ * Select database.
+ * @param string $database name of the database to select
+ * @param resource $dbh valid dbh, null if not defined
+ * @return bool success of command
+ */
+function db_select($database,$dbh=null)
+{
+ if(is_resource($dbh)){
+ return @mysql_select_db($database);
+ }else{
+ return @mysql_select_db($database, db_connect());
+ }
+
+}
+
+/**
+ * Execute a MySQL query.
+ * @param string $qry MySQL query
+ * @param resource $dbh valid dbh
+ */
+function db_query($qry=null,$dbh=null)
+{
+ static $result = null;
+ if(!is_resource($dbh)) $dbh = db_connect();
+ if(is_null($qry))
+ {
+ if(is_resource($result)) return $result;
+ else return false;
+ }
+ else
+ {
+ $result = @mysql_query($qry,$dbh);
+ return $result;
+ }
+}
+
+/**
+ * Fetch a row as an array from a result.
+ * @param string $result (default to null)
+ * @return array
+ */
+function db_fetch($result=null,$type=MYSQL_BOTH)
+{
+ return (!is_resource($result))? @mysql_fetch_array(db_query()) : @mysql_fetch_array($result,$type);
+}
+
+/**
+ * Fetch an array based on a query.
+ * @param string $query database query
+ * @param int $type result type
+ * @param string $col_id if passed it, the values of this column in the result set will be used as the array keys in the returned array
+ * @return array $list array of database rows
+ * Example of returned array:
+ * <code>
+ * db_get("SELECT * FROM table",MYSQL_ASSOC);
+ * returns...
+ * Array
+ * (
+ * [0] => Array
+ * (
+ * [id] => 1
+ * [field1] => data1
+ * [field2] => data2
+ * )
+ *
+ * )
+ * </code>
+ */
+function db_get($query,$type=MYSQL_BOTH,$col_id=NULL)
+{
+ $res = db_query($query);
+ $list = array();
+ if (is_resource($res) && !is_null($col_id) && ($type == MYSQL_BOTH || $type == MYSQL_ASSOC) && @mysql_num_rows($res) !== 0) {
+ $col_test = db_fetch($res,$type);
+ @mysql_data_seek($res, 0);
+ if (array_key_exists($col_id,$col_test)) {
+ while ( $buf = db_fetch($res,$type) ) {
+ $list[$buf[$col_id]] = $buf;
+ }
+ return $list;
+ }
+ }
+ while ( $buf = db_fetch($res,$type) ) {
+ $list[] = $buf;
+ }
+ return $list;
+}
+
+/**
+ * Get all of the fieldnames for the specified table.
+ * @param string $table name of table to describe
+ * @return array array of column names, must be an array
+ */
+function db_fieldnames($table)
+{
+ $dbh = db_connect();
+ $results = db_query("DESCRIBE $table");
+ if (is_resource($results))
+ {
+ while ($buf=db_fetch($results))
+ {
+ $field_names[] = $buf[0];
+ }
+ }
+ else
+ {
+ $field_names[] = 0;
+ }
+ return $field_names;
+}
+
+/**
+ * Create a MySQL INSERT statement based on $_POST array generated by form submission.
+ * <ul>
+ * <li>does not work with mysql functions (PASSWORD, etc.) because there are forced double quotes</li>
+ * <li>do not use clean_in() before this, or you'll have double the slashes</li>
+ * <li>use the function only when it saves you time, not _always_</li>
+ * <li>form items not set will not be processed (unchecked radios, checkboxes) - handle these manually, or don't use the func</li>
+ * </ul>
+ * @param array $vars array of posts
+ * @param string $table name of the table that fields will be inserted into
+ * @return string $query resulting MySQL insert string
+ */
+function db_makeinsert($vars,$table)
+{
+ $dbh = db_connect();
+ $fields = db_fieldnames($table);
+ foreach ($fields as $field)
+ {
+ if (get_magic_quotes_gpc) $vars[$field] = stripslashes($vars[$field]);
+ $vars[$field] = addslashes($vars[$field]);
+ if (isset($vars[$field]))
+ {
+ isset($q1)?$q1 .= ','.$field:$q1='INSERT INTO '.$table.'('.$field;
+ isset($q2)?$q2 .= ",'$vars[$field]'":$q2=" VALUES('$vars[$field]'";
+ }
+ }
+ $q1 .= ')';
+ $q2 .= ')';
+ $query = $q1.$q2;
+ return $query;
+}
+
+/**
+ * Create a MySQL REPLACE statement based on $_POST array generated by form submission.
+ * <ul>
+ * <li>does not work with mysql functions (PASSWORD, etc.) because there are forced double quotes</li>
+ * <li>do not use clean_in() before this, or you'll have double the slashes</li>
+ * <li>use the function only when it saves you time, not _always_</li>
+ * <li>form items not set will not be processed (unchecked radios, checkboxes) - handle these manually, or don't use the func</li>
+ * </ul>
+ * @param array $vars array of posts
+ * @param string $table name of the table that fields will be inserted into
+ * @return string $query resulting MySQL insert string
+ */
+function db_makereplace($vars,$table)
+{
+ $dbh = db_connect();
+ $fields = db_fieldnames($table);
+ foreach ($fields as $field)
+ {
+ if (get_magic_quotes_gpc) $vars[$field] = stripslashes($vars[$field]);
+ $vars[$field] = addslashes($vars[$field]);
+ if (isset($vars[$field]))
+ {
+ isset($q1)?$q1 .= ','.$field:$q1='REPLACE INTO '.$table.'('.$field;
+ isset($q2)?$q2 .= ",'$vars[$field]'":$q2=" VALUES('$vars[$field]'";
+ }
+ }
+ $q1 .= ')';
+ $q2 .= ')';
+ $query = $q1.$q2;
+ return $query;
+}
+
+/**
+ * Create a MySQL UPDATE statement based on $_POST array generated by form submission.
+ * <ul>
+ * <li>does not work with mysql functions (PASSWORD, etc.) because there are forced double quotes</li>
+ * <li>do not use clean_in() before this, or you'll have double the slashes</li>
+ * <li>use the function only when it saves you time, not _always_</li>
+ * <li>form items not set will not be processed (unchecked radios, checkboxes) - handle these manually, or don't use the func</li>
+ * </ul>
+ * @param array $vars array of posts
+ * @param string $table name of the table that fields will be inserted into
+ * @param string $where where clause, describing which records are to be updated
+ */
+function db_makeupdate($vars,$table,$where)
+{
+ $dbh = db_connect();
+ $fields = db_fieldnames($table);
+ foreach ($fields as $field)
+ {
+ if (isset($vars[$field]))
+ {
+ if (get_magic_quotes_gpc()) $vars[$field] = stripslashes($vars[$field]);
+ $vars[$field]=addslashes($vars[$field]);
+ $q1 = isset($q1)?$q1 .= ' ,'.$field."='$vars[$field]'":'UPDATE '.$table.' set '.$field."='$vars[$field]'";
+ }
+ }
+ $query = $q1.' '.$where;
+ return $query;
+}
+
+/**
+ * Since PHP's mysql_insert_id() sometimes throws an error, this is the replacement
+ * @param resource $dbh optional dbh to get the last inserted id from
+ * @return int the return value of MySQL's last_insert_id()
+ */
+function db_insert_id($dbh=null)
+{
+ if(!is_resource($dbh)) $dbh = db_connect();
+ $buf = db_fetch(db_query("SELECT LAST_INSERT_ID()", $dbh));
+ return empty($buf[0]) ? false : $buf[0];
+}
+
+/**
+ * Determine number of rows in result.
+ * @param resource $result mysql result
+ * @return int number of rows in query result
+ */
+function db_numrows($result=null)
+{
+ return (!is_resource($result))? @mysql_num_rows(db_query()) : @mysql_num_rows($result);
+}
+
+/**
+ * Close the db connection. If a dbh is not specified, assume the last opened link.
+ * @param resource $dbh optional dbh to close
+ */
+function db_close($dbh=null)
+{
+ return is_resource($dbh)?@mysql_close($dbh):@mysql_close();
+}
+
+/**
+ * Get one record.
+ * @param string $query query
+ * @param int $type result type
+ */
+function db_get_one($query,$type=MYSQL_ASSOC) {
+ $buf = db_get($query.' LIMIT 1',$type);
+ return $buf[0];
+}
+
+/**
+ * Get an ID based on name.
+ * @param string $table
+ * @param string $id_col
+ * @param string $name_col
+ * @param string $name
+ */
+function db_name_to_id($table,$id_col,$name_col,$name)
+{
+ $buf = db_get_one("SELECT {$id_col} FROM {$table} WHERE {$name_col} = '{$name}'", MYSQL_NUM);
+ return $buf[0];
+}
+
+/**
+ * Sets enum booleans to their opposite
+ * @param string $table
+ * @param string $pri
+ * @param string $col
+ * @param array $id
+ * @return int
+ */
+function db_toggle_bool($table, $pri, $col, $id)
+{
+ return db_query("UPDATE {$table} SET {$col} = IF({$col} = '1', '0', '1') WHERE {$pri} = {$id}");
+}
+?>
diff --git a/php/lib/db.php.orig b/php/lib/db.php.orig
new file mode 100644
index 0000000..23dd1ea
--- /dev/null
+++ b/php/lib/db.php.orig
@@ -0,0 +1,306 @@
+<?php
+/**
+ * Minimal wrappers for core PHP mysql_* functions.
+ * @package mirror
+ * @subpackage lib
+ */
+
+/**
+ * Connect to a MySQL database server.
+ * @param string $host db server, defaults to localhost
+ * @param string $user db username
+ * @param string $password db password
+ * @return resource dbh
+ */
+function db_connect($host='localhost',$user=null,$password=null)
+{
+ static $dbh = null;
+ if (!empty($host) && isset($user) && isset($password)) {
+ $dbh = @mysql_connect($host,$user,$password);
+ }
+ if (is_resource($dbh)) {
+ return $dbh;
+ }
+ else die("Unable to create database connection in db_connect()");
+}
+
+/**
+ * Select database.
+ * @param string $database name of the database to select
+ * @param resource $dbh valid dbh, null if not defined
+ * @return bool success of command
+ */
+function db_select($database,$dbh=null)
+{
+ if(is_resource($dbh)){
+ return @mysql_select_db($database);
+ }else{
+ return @mysql_select_db($database, db_connect());
+ }
+
+}
+
+/**
+ * Execute a MySQL query.
+ * @param string $qry MySQL query
+ * @param resource $dbh valid dbh
+ */
+function db_query($qry=null,$dbh=null)
+{
+ static $result = null;
+ if(!is_resource($dbh)) $dbh = db_connect();
+ printf("q:%s dbh=%s\n",$qry,$dbh);
+ if(is_null($qry))
+ {
+ if(is_resource($result)) return $result;
+ else return false;
+ }
+ else
+ {
+ $result = mysql_query($qry,$dbh);
+ return $result;
+ }
+}
+
+/**
+ * Fetch a row as an array from a result.
+ * @param string $result (default to null)
+ * @return array
+ */
+function db_fetch($result=null,$type=MYSQL_BOTH)
+{
+ if(!is_resource($result)) {
+ print 'Rerun query"'.$result.'"';
+ return @mysql_fetch_array(db_query());
+ } else {
+ return @mysql_fetch_array($result,$type);
+ }
+}
+
+/**
+ * Fetch an array based on a query.
+ * @param string $query database query
+ * @param int $type result type
+ * @param string $col_id if passed it, the values of this column in the result set will be used as the array keys in the returned array
+ * @return array $list array of database rows
+ * Example of returned array:
+ * <code>
+ * db_get("SELECT * FROM table",MYSQL_ASSOC);
+ * returns...
+ * Array
+ * (
+ * [0] => Array
+ * (
+ * [id] => 1
+ * [field1] => data1
+ * [field2] => data2
+ * )
+ *
+ * )
+ * </code>
+ */
+function db_get($query,$type=MYSQL_BOTH,$col_id=NULL)
+{
+ $res = db_query($query);
+ $list = array();
+ if (is_resource($res) && !is_null($col_id) && ($type == MYSQL_BOTH || $type == MYSQL_ASSOC) && @mysql_num_rows($res) !== 0) {
+ $col_test = db_fetch($res,$type);
+ @mysql_data_seek($res, 0);
+ if (array_key_exists($col_id,$col_test)) {
+ while ( $buf = db_fetch($res,$type) ) {
+ $list[$buf[$col_id]] = $buf;
+ }
+ return $list;
+ }
+ }
+ while ( $buf = db_fetch($res,$type) ) {
+ $list[] = $buf;
+ }
+ return $list;
+}
+
+/**
+ * Get all of the fieldnames for the specified table.
+ * @param string $table name of table to describe
+ * @return array array of column names, must be an array
+ */
+function db_fieldnames($table)
+{
+ $dbh = db_connect();
+ $results = db_query("DESCRIBE $table");
+ if (is_resource($results))
+ {
+ while ($buf=db_fetch($results))
+ {
+ $field_names[] = $buf[0];
+ }
+ }
+ else
+ {
+ $field_names[] = 0;
+ }
+ return $field_names;
+}
+
+/**
+ * Create a MySQL INSERT statement based on $_POST array generated by form submission.
+ * <ul>
+ * <li>does not work with mysql functions (PASSWORD, etc.) because there are forced double quotes</li>
+ * <li>do not use clean_in() before this, or you'll have double the slashes</li>
+ * <li>use the function only when it saves you time, not _always_</li>
+ * <li>form items not set will not be processed (unchecked radios, checkboxes) - handle these manually, or don't use the func</li>
+ * </ul>
+ * @param array $vars array of posts
+ * @param string $table name of the table that fields will be inserted into
+ * @return string $query resulting MySQL insert string
+ */
+function db_makeinsert($vars,$table)
+{
+ $dbh = db_connect();
+ $fields = db_fieldnames($table);
+ foreach ($fields as $field)
+ {
+ if (get_magic_quotes_gpc) $vars[$field] = stripslashes($vars[$field]);
+ $vars[$field] = addslashes($vars[$field]);
+ if (isset($vars[$field]))
+ {
+ isset($q1)?$q1 .= ','.$field:$q1='INSERT INTO '.$table.'('.$field;
+ isset($q2)?$q2 .= ",'$vars[$field]'":$q2=" VALUES('$vars[$field]'";
+ }
+ }
+ $q1 .= ')';
+ $q2 .= ')';
+ $query = $q1.$q2;
+ return $query;
+}
+
+/**
+ * Create a MySQL REPLACE statement based on $_POST array generated by form submission.
+ * <ul>
+ * <li>does not work with mysql functions (PASSWORD, etc.) because there are forced double quotes</li>
+ * <li>do not use clean_in() before this, or you'll have double the slashes</li>
+ * <li>use the function only when it saves you time, not _always_</li>
+ * <li>form items not set will not be processed (unchecked radios, checkboxes) - handle these manually, or don't use the func</li>
+ * </ul>
+ * @param array $vars array of posts
+ * @param string $table name of the table that fields will be inserted into
+ * @return string $query resulting MySQL insert string
+ */
+function db_makereplace($vars,$table)
+{
+ $dbh = db_connect();
+ $fields = db_fieldnames($table);
+ foreach ($fields as $field)
+ {
+ if (get_magic_quotes_gpc) $vars[$field] = stripslashes($vars[$field]);
+ $vars[$field] = addslashes($vars[$field]);
+ if (isset($vars[$field]))
+ {
+ isset($q1)?$q1 .= ','.$field:$q1='REPLACE INTO '.$table.'('.$field;
+ isset($q2)?$q2 .= ",'$vars[$field]'":$q2=" VALUES('$vars[$field]'";
+ }
+ }
+ $q1 .= ')';
+ $q2 .= ')';
+ $query = $q1.$q2;
+ return $query;
+}
+
+/**
+ * Create a MySQL UPDATE statement based on $_POST array generated by form submission.
+ * <ul>
+ * <li>does not work with mysql functions (PASSWORD, etc.) because there are forced double quotes</li>
+ * <li>do not use clean_in() before this, or you'll have double the slashes</li>
+ * <li>use the function only when it saves you time, not _always_</li>
+ * <li>form items not set will not be processed (unchecked radios, checkboxes) - handle these manually, or don't use the func</li>
+ * </ul>
+ * @param array $vars array of posts
+ * @param string $table name of the table that fields will be inserted into
+ * @param string $where where clause, describing which records are to be updated
+ */
+function db_makeupdate($vars,$table,$where)
+{
+ $dbh = db_connect();
+ $fields = db_fieldnames($table);
+ foreach ($fields as $field)
+ {
+ if (isset($vars[$field]))
+ {
+ if (get_magic_quotes_gpc()) $vars[$field] = stripslashes($vars[$field]);
+ $vars[$field]=addslashes($vars[$field]);
+ $q1 = isset($q1)?$q1 .= ' ,'.$field."='$vars[$field]'":'UPDATE '.$table.' set '.$field."='$vars[$field]'";
+ }
+ }
+ $query = $q1.' '.$where;
+ return $query;
+}
+
+/**
+ * Since PHP's mysql_insert_id() sometimes throws an error, this is the replacement
+ * @param resource $dbh optional dbh to get the last inserted id from
+ * @return int the return value of MySQL's last_insert_id()
+ */
+function db_insert_id($dbh=null)
+{
+ if(!is_resource($dbh)) $dbh = db_connect();
+ $buf = db_fetch(db_query("SELECT LAST_INSERT_ID()", $dbh));
+ return empty($buf[0]) ? false : $buf[0];
+}
+
+/**
+ * Determine number of rows in result.
+ * @param resource $result mysql result
+ * @return int number of rows in query result
+ */
+function db_numrows($result=null)
+{
+ return (!is_resource($result))? @mysql_num_rows(db_query()) : @mysql_num_rows($result);
+}
+
+/**
+ * Close the db connection. If a dbh is not specified, assume the last opened link.
+ * @param resource $dbh optional dbh to close
+ */
+function db_close($dbh=null)
+{
+ return is_resource($dbh)?@mysql_close($dbh):@mysql_close();
+}
+
+/**
+ * Get one record.
+ * @param string $query query
+ * @param int $type result type
+ */
+function db_get_one($query,$type=MYSQL_ASSOC) {
+ $buf = db_get($query.' LIMIT 1',$type);
+ return $buf[0];
+}
+
+/**
+ * Get an ID based on name.
+ * @param string $table
+ * @param string $id_col
+ * @param string $name_col
+ * @param string $name
+ */
+function db_name_to_id($table,$id_col,$name_col,$name)
+{
+ $q = "SELECT {$id_col} FROM {$table} WHERE {$name_col} = '{$name}'";
+ print 'Query: '.$q."<br />\n";
+ $buf = db_get_one($q, MYSQL_NUM);
+ return $buf[0];
+}
+
+/**
+ * Sets enum booleans to their opposite
+ * @param string $table
+ * @param string $pri
+ * @param string $col
+ * @param array $id
+ * @return int
+ */
+function db_toggle_bool($table, $pri, $col, $id)
+{
+ return db_query("UPDATE {$table} SET {$col} = IF({$col} = '1', '0', '1') WHERE {$pri} = {$id}");
+}
+?>
diff --git a/php/lib/forms.php b/php/lib/forms.php
new file mode 100644
index 0000000..0317949
--- /dev/null
+++ b/php/lib/forms.php
@@ -0,0 +1,659 @@
+<?php
+/**
+ * Form functions for handling form input, output, and markup.
+ * @package mirror
+ * @subpackage lib
+ */
+
+/**
+ * Cleans a string or an array of strings for HTML presentation.
+ * @param mixed $str dirty
+ * @param bool $slashes default to false, this parameter indicate if stripslashes is desired, usually use for magic qoutes
+ * @return mixed $str cleaned for HTML
+ */
+function clean_out($str, $slashes=FALSE)
+{
+ if (is_array($str))
+ {
+ foreach ($str as $key => $val)
+ {
+ $str[$key] =& clean_out($val, $slashes);
+ }
+ }
+ else
+ {
+ if ($slashes)
+ $str =& trim(htmlentities(stripslashes($str)));
+ else
+ $str =& trim(htmlentities($str));
+ }
+
+ return $str;
+}
+
+/**
+ * Cleans a string or an array of strings for DB input.
+ * @param mixed $str dirty
+ * @param bool $single_quote add single quotes around the string, optional
+ * @param bool $decode run html_entity_decode(), optional
+ * @return mixed $ret slashes added, if necessary
+ */
+function clean_in($str, $single_quotes=FALSE, $decode=FALSE)
+{
+ if (is_array($str))
+ {
+ foreach ($str as $key => $val)
+ {
+ $str[$key] =& clean_in($val, $single_quotes);
+ }
+ }
+ else
+ {
+ if (get_magic_quotes_gpc() === 1)
+ {
+ $str =& trim($str);
+ }
+ else
+ {
+ $str =& addslashes(trim($str));
+ }
+ if ($single_quotes) {
+ $str = "'" . $str . "'";
+ }
+ if ($decode) {
+ html_entity_decode($str);
+ }
+ }
+ return $str;
+}
+
+/**
+ * Get calendar days in array format.
+ * @param int $month numeric representation of month (optional) default is empty, accepted range value is 1-12 inclusive, this affects the total number of days in given month
+ * @param int $year the year (optional) default is empty, this affects the total number of days in given month
+ * @return array $days days from 1->[28-31] (zero-filled)
+ */
+function array_days($month='',$year='')
+{
+ $days = Array();
+ $num = 1;
+
+ // get total number of days of a particular month if given a month and year
+ if (!empty($month) && !empty($year) && is_numeric($month)
+ && is_numeric($year) && $month > 0 && $month < 13)
+ {
+ $days_inmonth = (int) date("t", strtotime($year."-".$month."-01"));
+ }
+ else
+ $days_inmonth = 31;
+
+ while ($num <= $days_inmonth)
+ {
+ // zero-fill
+ if ($num < 10) $num = "0$num";
+ else $num = "$num";
+ $days[$num] = $num;
+ $num++;
+ }
+ return $days;
+}
+
+/**
+ * Get calendar months in array format.
+ * @return array $months months from 01-12 (zero-filled)
+ */
+function array_months()
+{
+ $months=array(
+ '01' => 'Jan',
+ '02' => 'Feb',
+ '03' => 'Mar',
+ '04' => 'Apr',
+ '05' => 'May',
+ '06' => 'Jun',
+ '07' => 'Jul',
+ '08' => 'Aug',
+ '09' => 'Sep',
+ '10' => 'Oct',
+ '11' => 'Nov',
+ '12' => 'Dec',
+ );
+ return $months;
+}
+
+/**
+ * Get calendar years in array format.
+ * @param int $num number of years to display (optional) default is 5, negative numbers change direction of array
+ * @param int $year starting year (optional) default is this year
+ * @return array $years years
+ */
+function array_years($num=5,$year='')
+{
+ $years=Array();
+ $year=($year==null)?date('Y'):$year;
+ if ($num>0)
+ {
+ while ($num > 0)
+ {
+ $years[$year] = $year;
+ $year--;
+ $num--;
+ }
+ }
+ elseif ($num<0)
+ {
+ while ($num < 0)
+ {
+ $years[$year] = $year;
+ $year++;
+ $num++;
+ }
+ }
+ return $years;
+}
+
+/**
+ * Get calendar hours in array format.
+ * @return array $hours hours (zero-filled)
+ */
+function array_hours()
+{
+ $hours=array(
+ '07' => '7 am',
+ '08' => '8 am',
+ '09' => '9 am',
+ '10' => '10 am',
+ '11' => '11 am',
+ '12' => '12 pm',
+ '13' => '1 pm',
+ '14' => '2 pm',
+ '15' => '3 pm',
+ '16' => '4 pm',
+ '17' => '5 pm',
+ '18' => '6 pm',
+ '19' => '7 pm',
+ '20' => '8 pm',
+ '21' => '9 pm',
+ '22' => '10 pm',
+ );
+ return $hours;
+}
+
+/**
+ * Get array of minutes.
+ * @param int $interval interval between minutes (optional) default is 15
+ * @return array $minutes minutes (zero-filled)
+ */
+function array_minutes($interval=15)
+{
+ $minutes=array();
+ $count=$interval;
+ for ($i=0;$i<60;$i+=$interval)
+ {
+ $tmp=($i<10)?'0'.$i:$i;
+ $minutes[$tmp]=$tmp;
+ }
+ return $minutes;
+}
+
+/**
+ * Get array of states.
+ * @return array $states states (abbr=>fullname)
+ */
+function array_states()
+{
+ $states=array (
+ 'AL' => 'Alabama',
+ 'AK' => 'Alaska',
+ 'AS' => 'American Samoa',
+ 'AZ' => 'Arizona',
+ 'AR' => 'Arkansas',
+ 'CA' => 'California',
+ 'CO' => 'Colorado',
+ 'CT' => 'Connecticut',
+ 'DE' => 'Delaware',
+ 'DC' => 'District of Columbia',
+ 'FM' => 'Federated States of Micronesia',
+ 'FL' => 'Florida',
+ 'GA' => 'Georgia',
+ 'GU' => 'Guam',
+ 'HI' => 'Hawaii',
+ 'ID' => 'Idaho',
+ 'IL' => 'Illinois',
+ 'IN' => 'Indiana',
+ 'IA' => 'Iowa',
+ 'KS' => 'Kansas',
+ 'KY' => 'Kentucky',
+ 'LA' => 'Louisiana',
+ 'ME' => 'Maine',
+ 'MH' => 'Marshall Islands',
+ 'MD' => 'Maryland',
+ 'MA' => 'Massachusetts',
+ 'MI' => 'Michigan',
+ 'MN' => 'Minnesota',
+ 'MS' => 'Mississippi',
+ 'MO' => 'Missouri',
+ 'MT' => 'Montana',
+ 'NE' => 'Nebraska',
+ 'NV' => 'Nevada',
+ 'NH' => 'New Hampshire',
+ 'NJ' => 'New Jersey',
+ 'NM' => 'New Mexico',
+ 'NY' => 'New York',
+ 'NC' => 'North Carolina',
+ 'ND' => 'North Dakota',
+ 'MP' => 'Northern Mariana Islands',
+ 'OH' => 'Ohio',
+ 'OK' => 'Oklahoma',
+ 'OR' => 'Oregon',
+ 'PW' => 'Palau',
+ 'PA' => 'Pennsylvania',
+ 'PR' => 'Puerto Rico',
+ 'RI' => 'Rhode Island',
+ 'SC' => 'South Carolina',
+ 'SD' => 'South Dakota',
+ 'TN' => 'Tennessee',
+ 'TX' => 'Texas',
+ 'UT' => 'Utah',
+ 'VT' => 'Vermont',
+ 'VI' => 'Virgin Islands',
+ 'VA' => 'Virginia',
+ 'WA' => 'Washington',
+ 'WV' => 'West Virginia',
+ 'WI' => 'Wisconsin',
+ 'WY' => 'Wyoming'
+ );
+ return $states;
+}
+
+/**
+ * Writes the beginning form tag.
+ * @param string $name form name
+ * @param string $class class name
+ * @param string $method method (post or get)
+ * @param string $action action
+ */
+function form_start($name='form', $class=null, $method='post', $action=null, $extra=null)
+{
+ $query_string = (empty($_SERVER['QUERY_STRING'])) ? '' : '?'.htmlentities($_SERVER['QUERY_STRING']);
+ $action = (empty($action)) ? $_SERVER['PHP_SELF'].$query_string : $action;
+ echo "\n";
+ echo "<form name=\"$name\" id=\"$name\"";
+ echo ($class) ? " class=\"$class\"" : '';
+ echo " method=\"$method\" action=\"$action\" $extra>";
+}
+
+/**
+ * Writes the ending form tag.
+ */
+function form_end()
+{
+ echo "\n".'</form>';
+}
+
+/**
+ * Writes a form input label.
+ * @param string $text label text
+ * @param string $for id of corresponding field
+ * @param string $class class css class of label
+ * @param string $extra any extra parameters (optional)
+ */
+function form_label($text=null, $for=null, $class=null, $extra=null)
+{
+ if ($extra) {$extra = ' '.$extra;}
+ echo "\n";
+ echo '<label';
+ echo ($for) ? " for=\"$for\"" : '';
+ echo ($class) ? " class=\"$class\"" : '';
+ echo "$extra>$text</label>";
+}
+
+/**
+ * Writes a text input.
+ * @param string $name name of field
+ * @param string $id id of field, must be unique per page
+ * @param string $css css class
+ * @param string $value value
+ * @param int $size size of field
+ * @param int $maxlength maxlength of field
+ * @param string $extra any extra parameters (optional)
+ */
+function form_text($name, $id=null, $class=null, $value=null, $size='30', $maxlength='100', $extra=null)
+{
+ if ($extra) {$extra = ' '.$extra;}
+ echo '<input type="text" name="'.$name.'"';
+ echo ($id) ? " id=\"$id\"" : '';
+ echo ($class) ? " class=\"$class\"" : '';
+ echo ($value) ? " value=\"$value\"" : '';
+ echo " size=\"$size\" maxlength=\"$maxlength\"$extra />";
+}
+
+/**
+ * Writes a password input.
+ * @param string $name name of field
+ * @param string $id id of field, must be unique per page
+ * @param string $css css class
+ * @param int $size size of field (optional) default is 30
+ * @param int $maxlength maxlength of field (optional)
+ * @param string $extra any extra parameters (optional)
+ */
+function form_password($name, $id=null, $class=null, $size='30', $maxlength='100', $extra=null)
+{
+ if ($extra) {$extra = ' '.$extra; }
+ echo "\n";
+ echo "<input type=\"password\" name=\"$name\"";
+ echo ($id) ? " id=\"$id\"" : '';
+ echo ($class) ? " class=\"$class\"" : '';
+ echo " size=\"$size\" maxlength=\"$maxlength\"$extra />";
+}
+
+/**
+ * Writes a checkbox input.
+ * @param string $name name of field
+ * @param string $id id of field, must be unique per page
+ * @param string $class css class
+ * @param string $value value
+ * @param bool $checked checked?
+ * @param string $extra any extra parameters (optional)
+ */
+function form_checkbox($name, $id=null, $class=null, $value=null, $checked=0, $extra=null)
+{
+ if ($extra) {$extra = ' '.$extra;}
+ if ($checked == 1)
+ {
+ echo "\n";
+ echo "<input type=\"checkbox\" name=\"$name\"";
+ echo ($id) ? " id=\"$id\"" : '';
+ echo ($class) ? " class=\"$class\"" : '';
+ echo ($value) ? " value=\"$value\"" : '';
+ echo " checked=\"checked\"$extra />";
+ }
+ else
+ {
+ echo "\n";
+ echo "<input type=\"checkbox\" name=\"$name\"";
+ echo ($id) ? " id=\"$id\"" : '';
+ echo ($class) ? " class=\"$class\"" : '';
+ echo ($value) ? " value=\"$value\"" : '';
+ echo "$extra />";
+ }
+}
+
+/**
+ * Writes a radio input.
+ * @param string $name name of field
+ * @param string $id id of field, must be unique per page
+ * @param string $class css class
+ * @param string $value value
+ * @param bool $checked checked?
+ * @param string $extra any extra parameters (optional)
+ */
+function form_radio($name, $id=null, $class=null, $value=null, $checked=0, $extra=null)
+{
+ if ($extra) { $extra = ' '.$extra; }
+ if ($checked == 1)
+ {
+ echo "\n";
+ echo "<input type=\"radio\" name=\"$name\"";
+ echo ($id) ? " id=\"$id\"" : '';
+ echo ($class) ? " class=\"$class\"" : '';
+ echo ($value) ? " value=\"$value\"" : '';
+ echo " checked=\"checked\"$extra />";
+ }
+ else
+ {
+ echo "\n";
+ echo "<input type=\"radio\" name=\"$name\"";
+ echo ($id) ? " id=\"$id\"" : '';
+ echo ($class) ? " class=\"$class\"" : '';
+ echo ($value) ? " value=\"$value\"" : '';
+ echo "$extra />";
+ }
+}
+
+/**
+ * Writes a submit input.
+ * @param string $id the id attribute
+ * @param string $name name name of field
+ * @param string $class css class
+ * @param string $value value (button text)
+ * @param string $extra any extra parameters (optional)
+ */
+function form_submit($name, $id=null, $class=null, $value='Submit', $extra=null)
+{
+ if ($extra) {$extra = ' '.$extra;}
+ echo "\n";
+ echo "<input type=\"submit\" name=\"$name\"";
+ echo ($id) ? " id=\"$id\"" : '';
+ echo ($class) ? " class=\"$class\"" : '';
+ echo " value=\"$value\"$extra />";
+}
+
+/**
+ * Writes a reset input.
+ * @param string $name name of field
+ * @param string $class css class
+ * @param string $value value (button text)
+ * @param string $extra any extra parameters (optional)
+ */
+function form_reset($name, $class=null, $value='Reset', $extra=null)
+{
+ if ($extra) {$extra = ' '.$extra;}
+ echo "\n";
+ echo "<input type=\"reset\" name=\"$name\" id=\"$name\"";
+ echo ($class) ? " class=\"$class\"" : '';
+ echo " value=\"$value\"$extra />";
+}
+
+/**
+ * Writes a hidden field.
+ * @param string $name name of field
+ * @param string $value value
+ * @param string $extra any extra parameters (optional)
+ */
+function form_hidden($name, $value=null, $extra=null)
+{
+ if ($extra) {$extra = ' '.$extra;}
+ echo "\n";
+ echo "<input type=\"hidden\" name=\"$name\"";
+ echo ($value) ? " value=\"$value\"" : '';
+ echo "$extra />";
+}
+
+/**
+ * Writes a select list with options.
+ * @param string $name name of field
+ * @param string $id id of field, must be unique per page
+ * @param string $class css class
+ * @param array $options possible options, usually pulled from db, or array_* funcs
+ * @param string $selected if the value matches, it is selected
+ *
+ * Multiple selects based on sets come out of a database as val,val,val
+ * so the explode was intended to create the instance of an array based
+ * on the string regardless of whether or not it has val,val,val.
+ *
+ * @param string $extra any extra parameters (optional)
+ */
+function form_select($name, $id=null, $class=null, $options=null, $selected=null, $extra=null)
+{
+ if ($extra) {$extra = ' '.$extra;}
+ if (!empty($selected))
+ {
+ $selected = explode(',',$selected);
+ foreach ($selected as $key=>$val) {$selected[$key]=trim($val);}
+ }
+ echo "\n";
+ echo "<select name=\"$name\"";
+ echo ($id) ? " id=\"$id\"" : '';
+ echo ($class) ? " class=\"$class\"" : '';
+ echo "$extra>";
+ if (is_array($options))
+ {
+ foreach ($options as $key=>$val)
+ {
+ if (!empty($selected) && in_array($key, $selected))
+ echo "\n\t".'<option value="'.$key.'" selected="selected">'.$val.'</option>';
+ else
+ echo "\n\t".'<option value="'.$key.'">'.$val.'</option>';
+ }
+ }
+ echo "\n".'</select>';
+}
+
+/**
+ * Writes a textarea
+ * @param string $name name of field
+ * @param string $id id of field, must be unique per page
+ * @param string $class css class
+ * @param int $rows number of rows (height)
+ * @param int $cols number of cols (width)
+ * @param string $value value of field
+ * @param string $extra any extra parameters
+ */
+function form_textarea($name, $id=null, $class=null, $rows='6', $cols='50', $value=null, $extra=null)
+{
+ if ($extra) {$extra = ' '.$extra;}
+ echo "\n";
+ echo "<textarea name=\"$name\"";
+ echo ($id) ? " id=\"$id\"" : '';
+ echo ($class) ? " class=\"$class\"" : '';
+ echo " rows=\"$rows\" cols=\"$cols\"";
+ echo "$extra>$value</textarea>";
+}
+
+/**
+ * Fix dates for form display, or proper db entry
+ * @param array $dates array of date field names
+ * @param array $datetimes array of datetime field names
+ * @param int $way 1 is done after a post, 2 is done when selecting for forms
+ * @param array $orig for way 2, the array we need to add the separated date values to (usually $posts)
+ * @return mixed null, or the original array modified to have separated date values for the forms
+ */
+function form_array_fix_dates($dates,$datetimes,$way=1,$orig='')
+{
+ if($way==1)
+ {
+ if (is_array($dates))
+ {
+ foreach ($dates as $date)
+ {
+ $_POST[$date]=form_array_get_date($date);
+ }
+ }
+ if (is_array($datetimes))
+ {
+ foreach ($datetimes as $datetime)
+ {
+ $_POST[$datetime]=form_array_get_datetime($datetime);
+ }
+ }
+ }
+ elseif ($way==2)
+ {
+ if (is_array($dates))
+ {
+ foreach ($dates as $date)
+ {
+ list(${date.'_year'},${date.'_month'},${date.'_day'})=explode('-',$orig[$date]);
+ $orig[$date.'_year']=${date.'_year'};
+ $orig[$date.'_month']=${date.'_month'};
+ $orig[$date.'_day']=${date.'_day'};
+ }
+ }
+ if (is_array($datetimes))
+ {
+ foreach ($datetimes as $datetime)
+ {
+ $buf=explode(' ',$orig[$datetime]);
+ $date=explode('-',$buf[0]);
+ $time=explode(':',$buf[1]);
+ $orig[$datetime.'_year']=$date[0];
+ $orig[$datetime.'_month']=$date[1];
+ $orig[$datetime.'_day']=$date[2];
+ $orig[$datetime.'_hour']=$time[0];
+ $orig[$datetime.'_minute']=$time[1];
+ }
+ }
+ return $orig;
+ }
+}
+
+/**
+ * Get put a date back together after a POST.
+ * @param string $field name of post index of date field
+ * @param int $key index of form array that the field value belongs to
+ * @return array $date repaired date, as an array that corresponds to the form
+ */
+function form_array_get_date($field)
+{
+ $keys=array_keys($_POST[$field.'_year']);
+ foreach ($keys as $key)
+ {
+ $date[$key]=$_POST[$field.'_year'][$key].'-'.$_POST[$field.'_month'][$key].'-'.$_POST[$field.'_day'][$key];
+ }
+ return $date;
+}
+
+/**
+ * Get put a datetime back together after a POST.
+ * @param string $field name of post index of datetime field
+ * @param int $key index of form array that the field value belongs to
+ * @return array $datetime repaired datetime, as an array that corresponds to the form
+ */
+function form_array_get_datetime($field)
+{
+ $keys=array_keys($_POST[$field.'_year']);
+ foreach ($keys as $key)
+ {
+ $datetime[$key]=$_POST[$field.'_year'][$key].'-'.$_POST[$field.'_month'][$key].'-'.$_POST[$field.'_day'][$key].' '.$_POST[$field.'_hour'][$key].':'.$_POST[$field.'_minute'][$key];
+ }
+ return $datetime;
+}
+
+/**
+ * Validates email addresses
+ * @param string $email
+ * @returns bool
+ */
+function is_email_address($email)
+{
+ return preg_match("/^ *[0-9a-zA-Z]+[-_\.0-9a-zA-Z]*@([0-9a-zA-Z]+[-\.0-9a-zA-Z]+)+\.[a-zA-Z]+ *$/", $email);
+}
+
+/**
+ * Validates phone number
+ * @param string $phone
+ * @returns bool
+ */
+function is_phone_number($phone)
+{
+ return preg_match("/^ *((1[- \.]?((\([0-9]{3}\))|([0-9]{3}))[- \.]?)|((((\([0-9]{3}\))|([0-9]{3}))[- \.]?)?))[0-9]{3}[- \.]?[0-9]{4} *$/", $phone);
+}
+
+/**
+ * Returns http:// and the string if the string does not begin with http://
+ * @param string $url
+ * @returns string
+ */
+function url_out($url)
+{
+ return (preg_match("#^http://#", $url)) ? trim($url) : 'http://'.trim($url);
+}
+
+/**
+ * Take a db_get result and return an array of options.
+ * @param array $data db_get result
+ * @param string $val_col column containing the value for each option
+ * @param string $name_col column containing the text
+ * @return array $options array of options ($val=>$text)
+ */
+function db_get_to_options($data,$val_col,$name_col)
+{
+ $options=array();
+ foreach ($data as $row)
+ {
+ $options[$row[$val_col]]=$row[$name_col];
+ }
+ return $options;
+}
+?>
diff --git a/php/lib/geo.php b/php/lib/geo.php
new file mode 100644
index 0000000..bd80744
--- /dev/null
+++ b/php/lib/geo.php
@@ -0,0 +1,69 @@
+<?php
+/**
+ * Functions for netgeo lookups.
+ * @package mirror
+ * @subpackage lib
+ */
+
+/**
+ * Calculate the distance between two geo points.
+ * @param int $lat1 latitude of first point
+ * @param int $lon1 longitude of first point
+ * @param int $lat2 latitude of second point
+ * @param int $lon2 longitude of second point
+ * @return int $distance rounded distance in _km_ between these points
+ */
+function geo_get_distance($lat1,$lon1,$lat2,$lon2)
+{
+ return null;
+}
+
+/**
+ * Query NetGeo based on API and parse results.
+ * @param string $ip an IP address
+ * @param string $method lookup method, based on NetGeo API.
+ * @return array|false array containing results or false on failure
+ */
+function geo_query($ip,$method='getRecord')
+{
+ $raw = strip_tags(file_get_contents(GEO_URL.'?target='.$ip.'&method='.$method));
+ $lines = array_slice(explode("\n",$raw),5);
+ array_pop($lines);
+ foreach ($lines as $row)
+ {
+ $buf = preg_split('/:\s*/',$row);
+ $data[$buf[0]] = $buf[1];
+ }
+ return $data;
+}
+
+/**
+ * Get longitude and latitude of an IP.
+ * @param string $ip an IP address
+ * @return array|false array containing results or false on failure
+ */
+function geo_get_coordinates($ip)
+{
+ return ($data = geo_query($ip,'getLatLong'))?array('lat'=>$data['LAT'],'long'=>$data['LONG']):false;
+}
+
+/**
+ * Get complete record based on IP.
+ * @param string $ip an IP address
+ * @return array|false array containing results or false on failure
+ */
+function geo_get_record($ip)
+{
+ return ($data = geo_query($ip,'getRecord'))?$data:false;
+}
+
+/**
+ * Get country of an IP.
+ * @param string $ip an IP address
+ * @return string|false array containing results or false on failure
+ */
+function geo_get_country($ip)
+{
+ return ($data = geo_query($ip,'getCountry'))?$data['COUNTRY']:false;
+}
+?>
diff --git a/php/lib/list.php b/php/lib/list.php
new file mode 100644
index 0000000..5deb5e9
--- /dev/null
+++ b/php/lib/list.php
@@ -0,0 +1,391 @@
+<?php
+/**
+ * List functions for lists of values.
+ * @package mirror
+ * @subpackage lib
+ * @author Mike Morgan <mike.morgan@oregonstate.edu>
+ *
+ * Usage example:
+ * <code>
+ * $orderby=get_order();
+ * $query="SELECT * FROM fic_courses $orderby";
+ * $courses=db_get($query,MYSQL_ASSOC);
+ * $headers=array(
+ * 'course_id'=>'',
+ * 'title'=>'Course Title',
+ * 'date_start_course'=>'Start',
+ * 'date_end_course'=>'End',
+ * 'date_start_reg'=>'Reg Starts',
+ * 'date_end_reg'=>'Reg Ends',
+ * 'active'=>'Active?',
+ * 'entry_date'=>'Created'
+ * );
+ * show_list($courses,$headers);
+ * </code>
+ *
+ * Accompanying CSS for table output:
+ * <code>
+ * .list
+ * {
+ * border:1px solid #999;
+ * }
+ * .list th
+ * {
+ * background:#eee;
+ * border:1px solid #000;
+ * font-weight:bold;
+ * }
+ * .list th a
+ * {
+ * display:block;
+ * padding:0 14px;
+ * }
+ * .list th a:hover
+ * {
+ * background-color:#fff;
+ * }
+ * .row1
+ * {
+ * background:#ddd;
+ * }
+ * .row2
+ * {
+ * background:#ccc;
+ * }
+ * .row1:hover, .row2:hover
+ * {
+ * background-color:#fec;
+ * }
+ * .current-sort
+ * {
+ * background:#fda;
+ * }
+ * .sort-desc
+ * {
+ * background:#fec url(../img/up.gif) no-repeat right;
+ * }
+ * .sort-asc
+ * {
+ * background:#fec url(../img/down.gif) no-repeat right;
+ * }
+ * </code>
+
+ * Accompanying JavaScript for select all / inverse:
+ * <code>
+ * <script type="text/javascript">
+ * //<!--
+ * function selectAll(formObj,invert)
+ * {
+ * for (var i=0;i < formObj.elements.length;i++)
+ * {
+ * fldObj = formObj.elements[i];
+ * if (fldObj.type == 'checkbox')
+ * {
+ * if (invert==1)
+ * {
+ * fldObj.checked = (fldObj.checked) ? false : true;
+ * }
+ * else
+ * {
+ * fldObj.checked = true;
+ * }
+ * }
+ * }
+ * }
+ * //-->
+ * </script>
+ * </code>
+ */
+
+/**
+ * Show a list of values, for forms.
+ * @param array $list associative array
+ * @param array $headers column name => column title (for table heads)
+ * @param string $type checkbox, radio, simple
+ * @param array $array actions to display in actions select list
+ * @param string $form_id id of form holding list
+ * @param bool $sortable whether or not to show sortable column headers (links in th's)
+ * @param array|string $selected if type is checkbox, array otherwise string with one val
+ */
+function show_list($list,$headers,$type='checkbox',$actions=null,$form_id=null,$sortable=true,$selected=null)
+{
+ if ( is_array($list) && count($list)>0 && is_array($headers) )
+ {
+ if ( $type!='simple' && !empty($_GET['sort']) && !empty($_GET['order']) )
+ {
+ form_hidden('sort',$_GET['sort']);
+ form_hidden('order',$_GET['order']);
+ }
+ echo "\n".'<table class="list">';
+ show_headers($headers,$type,$sortable);
+ echo "\n".'<tbody>';
+ foreach ($list as $row)
+ {
+ show_row($headers,$row,$type,$count++,$selected);
+ }
+ echo "\n".'</tbody>';
+ echo "\n".'</table>';
+ if ($type=='checkbox')
+ {
+echo <<<js
+<script type="text/javascript">
+//<!--
+function list_select(formObj,invert)
+{
+ for (var i=0;i < formObj.elements.length;i++)
+ {
+ fldObj = formObj.elements[i];
+ if (fldObj.type == 'checkbox')
+ {
+ if (invert==1)
+ {
+ fldObj.checked = (fldObj.checked) ? false : true;
+ }
+ else
+ {
+ fldObj.checked = true;
+ }
+ }
+ }
+}
+//-->
+</script>
+js;
+ echo "\n".'<p><input type="button" name="selectall" onclick="list_select(this.form,0);" class="button2" value="Select All"/> <input type="button" name="selectall" onclick="list_select(this.form,1);" class="button2" value="Invert"/></p>';
+ }
+ if ($type=='radio'||$type='checkbox-small')
+ {
+ echo '<br />';
+ }
+ if (is_array($actions)&&$type!='simple')
+ {
+ if (count($actions) == 1) {
+ $actions = array_values($actions);
+ echo '<p>';
+ form_submit('submit','submit','button1',$actions[0].' &raquo;');
+ echo '</p>';
+ } else {
+ echo '<p>';
+ echo '<label for="action">With selected: </label>';
+ form_select('action','action','text2',$actions,'');
+ form_submit('submit','submit','button1','Go &raquo;');
+ echo '</p>';
+ }
+ }
+ }
+ elseif ( !is_array($headers) )
+ {
+ echo "\n".'<h1>FIX HEADERS ARRAY</h1>';
+ }
+ else
+ {
+ echo "\n".'<p>No records found.</p>';
+ }
+}
+
+/**
+ * Show table headers.
+ * @param array $headers column name => column title (for table heads)
+ * @param string $type type of list that is being shown
+ * @param bool $sortable whether or not to show sortable column headers (links in th's)
+ */
+function show_headers($headers,$type,$sortable=true)
+{
+ echo "\n".'<thead><tr>';
+ $sort=$_GET['sort'];
+ $order=get_order();
+ $count=0;
+ foreach ($headers as $col=>$title)
+ {
+ if ( !empty($sort) && !empty($order) )
+ {
+ if ($col==$sort && $order=='ASC')
+ {
+ $a_class=' class="sort-asc current-sort" ';
+ }
+ elseif ($col==$sort && $order=='DESC')
+ {
+ $a_class=' class="sort-desc current-sort" ';
+ }
+ else
+ {
+ $a_class=null;
+ }
+ }
+ if ($type!='simple'&&$count==0)
+ {
+ echo "\n".'<th> </th>';
+ next;
+ }
+ elseif($sortable)
+ {
+ $qs = array();
+ foreach ($_GET as $qn=>$qv) { $qs[$qn] = $qv; } // existing query string variables
+ $qs['sort'] = $col; // add/replace sort to query string
+ $qs['order'] = $order; // add/replace order by to query string
+ foreach ($qs as $qn=>$qv) { $querystring[] = $qn.'='.$qv; } // existing query string variables
+ echo "\n".'<th><a '.$a_class.'href="'.$_SERVER['PHP_SELF'].'?'.implode('&amp;',$querystring).'">'.$title.'</a></th>';
+ unset($qs);
+ unset($querystring);
+ }
+ else
+ {
+ echo "\n".'<th>'.$title.'</th>';
+ }
+ $count++;
+ }
+ echo "\n".'</tr></thead>';
+}
+
+/**
+ * Show table data.
+ * @param array $headers column name => column title (for knowing which ones to display)
+ * @param array $row table row, assoc
+ * @param string $type type of table, determines first column, which could be an input
+ * @param array|string $selected selected items; if type is checkbox, array otherwise string with one val
+ */
+function show_row($headers,$row,$type,$num=null,$selected=null)
+{
+ $indexes=array_keys($headers);
+ $idname = $indexes[0];
+ $count=0;
+ $tr_class=($num%2)?' class="row1" ':' class="row2" ';
+ echo "\n".'<tr'.$tr_class.'>';
+ foreach ($indexes as $index)
+ {
+ $row[$index]=clean_out($row[$index]);
+ if ($type!='simple'&&$count==0)
+ {
+ $id=preg_replace('/[^[:alnum:]]/', '', $index).$row[$index];
+ if ($type=='checkbox'||$type=='checkbox-small')
+ {
+ echo "\n".'<td>';
+ form_checkbox($idname.'[]',$id,null,$row[$index],(is_array($selected) && in_array($row[$index], $selected)));
+ echo "\n".'</td>';
+ }
+ elseif ($type=='radio')
+ {
+ echo "\n".'<td>';
+ form_radio($idname,$id,null,$row[$index], ($row[$index] == $selected));
+ echo "\n".'</td>';
+ }
+ }
+ else
+ {
+ echo ($type=='simple')?"\n".'<td>'.$row[$index].'</td>':"\n".'<td><label for="'.$id.'">'.$row[$index].'</label></td>';
+ }
+ $count++;
+ }
+ echo "\n".'</tr>';
+}
+
+/**
+ * Determine current sort order.
+ */
+function get_order()
+{
+ return ($_GET['order']=='ASC')?'DESC':'ASC';
+}
+
+/**
+ * Determine whether or not list is currently sorted.
+ * @param string $method which http method to check for sort information
+ * @return mixed cleaned orderby clause based on saved sort information or null if no orderby is set in the defined method
+ */
+function get_orderby($method='get')
+{
+ if ( $method=='get' && !empty($_GET['sort']) && !empty($_GET['order']) )
+ {
+ $sort=clean_in($_GET['sort']);
+ $order=clean_in($_GET['order']);
+ return " ORDER BY $sort $order ";
+ }
+ elseif ( $method=='post' && !empty($_POST['sort']) && !empty($_POST['order']) )
+ {
+ $sort=clean_in($_POST['sort']);
+ $order=clean_in($_POST['order']);
+ return " ORDER BY $sort $order ";
+ }
+ elseif ( $method=='session' && !empty($_SESSION['sort']) && !empty($_SESSION['order']) )
+ {
+ $sort=clean_in($_SESSION['sort']);
+ $order=clean_in($_SESSION['order']);
+ return " ORDER BY $sort $order ";
+ }
+ else return null;
+}
+
+/**
+ * Parses $_POST for ids, shows edit forms for each id with populated data.
+ * <ul>
+ * <li>name will be used to retrieve an _array_ from $_POST of the same name</li>
+ * <li>the form will be an include, with $posts[col_name] as the default for all values</li>
+ * <li>try to keep your query simple (no crazy sorting, etc.) -- we're talking one record at a time here anyway</li>
+ * </ul>
+ * Example:
+ * <code>
+ * list_edit_ids('course_id','../forms/course.php','SELECT * FROM fic_courses','1');
+ * </code>
+ * @param string $name name of id field
+ * @param string $form path to form to be used to items
+ * @param string $q_front front half of query
+ * @param string $q_where where statement
+ * @param array $dates array of date field names, so they can be fixed for forms
+ * @param array $datetimes array of datetime field names, so they can be fixed for forms
+ */
+function list_edit_ids($name,$form,$q_front,$q_where='1',$dates=null,$datetimes=null)
+{
+ if ( !empty($_SESSION[$name]) && is_array($_SESSION[$name]) )
+ {
+ $ids=implode(',',$_SESSION[$name]);
+ $orderby=get_orderby('session');
+ $query=$q_front.' WHERE '.$q_where." AND $name IN($ids) ".$orderby;
+ $records=db_get($query);
+ form_start($name);
+ foreach ($records as $record)
+ {
+ echo "\n".'<div class="record">';
+ $record=form_array_fix_dates($dates,$datetimes,2,$record);
+ foreach ($record as $key=>$val)
+ {
+ $posts[$key]=clean_out($val);
+ }
+ include($form);
+ echo "\n".'<div class="record-submit">';
+ form_submit('submit', '', 'button1');
+ echo "\n".'</div>';
+ echo "\n".'</div>';
+ }
+ form_end();
+ }
+ else
+ {
+ echo '<p>You must select a record. <a href="javascript:history.back();">Go back</a>.</p>';
+ }
+}
+
+/**
+ * Process a submitted list_edit_ids form.
+ * @param array $name array of primary ids posted from the form, these are vital to the WHERE clause of the UPDATE statements.
+ * @param string $table name of table being affected
+ */
+function list_update_ids($name,$table)
+{
+ $keys=array_keys($_POST[$name]);
+ foreach ($keys as $index)
+ {
+ foreach ($_POST as $key=>$val)
+ {
+ if ($key!='submit')
+ {
+ $posts[$index][$key]=$val[$index];
+ }
+ }
+ }
+ foreach ($posts as $dataset)
+ {
+ $query=db_makeupdate($dataset,$table," WHERE $name='".$dataset[$name]."' ");
+ db_query($query);
+ }
+}
+?>
diff --git a/php/lib/mirror.php b/php/lib/mirror.php
new file mode 100644
index 0000000..a618a86
--- /dev/null
+++ b/php/lib/mirror.php
@@ -0,0 +1,531 @@
+<?php
+/**
+ * Application functions. Dependent on lib/db.php!
+ * @package mirror
+ * @subpackage lib
+ * @todo add transactions once innodb table types are in place
+ */
+
+/**
+ * Get an alpha-list of regions for select list.
+ * @return array $regions
+ */
+function mirror_get_regions_select()
+{
+ $regions = db_get("SELECT region_id,region_name FROM mirror_regions ORDER BY region_name ASC",MYSQL_ASSOC);
+ foreach ($regions as $region) {
+ $retval[$region['region_id']]=$region['region_name'];
+ }
+ return $retval;
+}
+
+/**
+ * Get an priority-list of regions for select list.
+ * @return array $regions
+ */
+function mirror_get_regions_select_priority()
+{
+ $regions = db_get("SELECT region_id,region_name FROM mirror_regions ORDER BY region_priority ASC",MYSQL_ASSOC);
+ foreach ($regions as $region) {
+ $retval[$region['region_id']]=$region['region_name'];
+ }
+ return $retval;
+}
+
+/**
+ * Insert region.
+ * @param string $name
+ * @param int $priority
+ * @return bool
+ */
+function mirror_insert_region($name,$priority)
+{
+ return db_query("INSERT INTO mirror_regions(region_name,region_priority) VALUES('{$name}',{$priority})");
+}
+
+/**
+ * Update region.
+ * @param int $id
+ * @param string $name
+ * @param int $priority
+ * @return bool
+ */
+function mirror_update_region($id,$name,$priority)
+{
+ return db_query("UPDATE mirror_regions SET region_name='{$name}',region_priority={$priority} WHERE region_id={$id}");
+}
+
+/**
+ * Get one region.
+ * @param int $id
+ * @return array
+ */
+function mirror_get_one_region($id)
+{
+ return db_get_one("SELECT * FROM mirror_regions WHERE region_id = {$id}");
+}
+
+/**
+ * Delete a region.
+ * @param int $id
+ * @return bool
+ */
+function mirror_delete_region($id)
+{
+ return db_query("DELETE FROM mirror_regions WHERE region_id={$id}");
+}
+
+/**
+ * Get an alpha-list of mirrors for select list.
+ * @return array $mirrors
+ */
+function mirror_get_mirrors_select()
+{
+ $mirrors = db_get("SELECT mirror_id,mirror_name FROM mirror_mirrors ORDER BY mirror_name ASC",MYSQL_ASSOC);
+ foreach ($mirrors as $mirror) {
+ $retval[$mirror['mirror_id']]=$mirror['mirror_name'];
+ }
+ return $retval;
+}
+
+/**
+ * Get regions.
+ * @return array
+ */
+function mirror_get_regions()
+{
+ return db_get("
+ SELECT
+ mirror_regions.*,
+ COUNT(mirror_id) as mirrors
+ FROM
+ mirror_regions
+ LEFT JOIN
+ mirror_mirror_region_map
+ ON
+ mirror_regions.region_id = mirror_mirror_region_map.region_id
+ GROUP BY
+ mirror_regions.region_id
+ ",MYSQL_ASSOC);
+}
+
+/**
+ * Insert mirror.
+ * @param string $name
+ * @param int $region_id
+ * @param string $baseurl
+ * @param int $rating
+ * @return bool
+ */
+function mirror_insert_mirror($name,$region_id,$baseurl,$rating)
+{
+ return (db_query("INSERT INTO mirror_mirrors(mirror_name,mirror_baseurl,mirror_rating) VALUES('{$name}','{$baseurl}','{$rating}')") && db_query("INSERT INTO mirror_mirror_region_map(mirror_id,region_id) VALUES('".db_insert_id()."','$region_id')"))?true:false;
+}
+
+/**
+ * Update mirror.
+ * @param string $name
+ * @param int $region_id
+ * @param string $baseurl
+ * @param int $rating
+ * @return bool
+ */
+function mirror_update_mirror($id,$name,$region_id,$baseurl,$rating)
+{
+ return (db_query("UPDATE mirror_mirrors SET mirror_name='{$name}',mirror_baseurl='{$baseurl}',mirror_rating='{$rating}' WHERE mirror_id={$id}") && db_query("UPDATE mirror_mirror_region_map SET region_id={$region_id} WHERE mirror_id={$id}"))?true:false;
+}
+
+/**
+ * Delete mirror.
+ * @return bool
+ */
+function mirror_delete_mirror($mirror_id)
+{
+ return (db_query("DELETE FROM mirror_mirrors WHERE mirror_id={$mirror_id}")&&db_query("DELETE FROM mirror_mirror_region_map WHERE mirror_id={$mirror_id}"))?true:false;
+}
+
+/**
+ * Get one mirror record.
+ * @param int $mirror_id
+ * @return array mirror information
+ */
+function mirror_get_one_mirror($mirror_id)
+{
+ return db_get_one("SELECT mirror_mirrors.*,region_id FROM mirror_mirrors,mirror_mirror_region_map WHERE mirror_mirrors.mirror_id={$mirror_id} AND mirror_mirrors.mirror_id=mirror_mirror_region_map.mirror_id");
+}
+
+/**
+ * Get list of mirrors.
+ * @return array
+ */
+function mirror_get_mirrors()
+{
+ return db_get("
+ SELECT
+ mirror_mirrors.*,
+ IF(mirror_mirrors.mirror_active='0','DISABLED','ok') as mirror_active,
+ region_name
+ FROM
+ mirror_mirrors,
+ mirror_regions,
+ mirror_mirror_region_map
+ WHERE
+ mirror_regions.region_id = mirror_mirror_region_map.region_id AND
+ mirror_mirrors.mirror_id = mirror_mirror_region_map.mirror_id
+ ",MYSQL_ASSOC);
+}
+
+/**
+ * Insert product.
+ * @param string $name
+ * @param int $priority
+ * @return bool
+ */
+function mirror_insert_product($name,$priority)
+{
+ return db_query("INSERT INTO mirror_products(product_name,product_priority) VALUES('{$name}',{$priority})");
+}
+
+/**
+ * Update product.
+ * @param int $id
+ * @param string $name
+ * @param int $priority
+ * @return bool
+ */
+function mirror_update_product($id,$name,$priority)
+{
+ return db_query("UPDATE mirror_products SET product_name='{$name}',product_priority={$priority} WHERE product_id={$id}");
+}
+
+/**
+ * Get one product.
+ * @param int $id
+ * @return array
+ */
+function mirror_get_one_product($id)
+{
+ return db_get_one("SELECT * FROM mirror_products WHERE product_id = {$id}");
+}
+
+/**
+ * Delete a product.
+ * @param int $id
+ * @return bool
+ */
+function mirror_delete_product($id)
+{
+ return db_query("DELETE FROM mirror_products WHERE product_id={$id}");
+}
+
+/**
+ * Get products.
+ * @return array
+ */
+function mirror_get_products()
+{
+ return db_get("
+ SELECT
+ *
+ FROM
+ mirror_products
+ ",MYSQL_ASSOC);
+}
+
+/**
+ * Insert os.
+ * @param string $name
+ * @param int $priority
+ * @return bool
+ */
+function mirror_insert_os($name,$priority)
+{
+ return db_query("INSERT INTO mirror_os(os_name,os_priority) VALUES('{$name}',{$priority})");
+}
+
+/**
+ * Update os.
+ * @param int $id
+ * @param string $name
+ * @param int $priority
+ * @return bool
+ */
+function mirror_update_os($id,$name,$priority)
+{
+ return db_query("UPDATE mirror_os SET os_name='{$name}',os_priority={$priority} WHERE os_id={$id}");
+}
+
+/**
+ * Get one os.
+ * @param int $id
+ * @return array
+ */
+function mirror_get_one_os($id)
+{
+ return db_get_one("SELECT * FROM mirror_os WHERE os_id = {$id}");
+}
+
+/**
+ * Delete a os.
+ * @param int $id
+ * @return bool
+ */
+function mirror_delete_os($id)
+{
+ return db_query("DELETE FROM mirror_os WHERE os_id={$id}");
+}
+
+/**
+ * Get operating systems.
+ * @return array
+ */
+function mirror_get_oss()
+{
+ return db_get("
+ SELECT
+ *
+ FROM
+ mirror_os
+ ",MYSQL_ASSOC);
+}
+
+/**
+ * Get an alpha-list of operating systems for select list.
+ * @return array $oss
+ */
+function mirror_get_oss_select()
+{
+ $oss = db_get("SELECT os_id,os_name FROM mirror_os ORDER BY os_name ASC",MYSQL_ASSOC);
+ foreach ($oss as $os) {
+ $retval[$os['os_id']]=$os['os_name'];
+ }
+ return $retval;
+}
+
+/**
+ * Get an priority-list of operating systems for select list.
+ * @return array $oss
+ */
+function mirror_get_oss_select_priority()
+{
+ $oss = db_get("SELECT os_id,os_name FROM mirror_os ORDER BY os_priority ASC",MYSQL_ASSOC);
+ foreach ($oss as $os) {
+ $retval[$os['os_id']]=$os['os_name'];
+ }
+ return $retval;
+}
+
+/**
+ * Get an alpha-list of products for select list.
+ * @return array $products
+ */
+function mirror_get_products_select()
+{
+ $products = db_get("SELECT product_id,product_name FROM mirror_products ORDER BY product_name ASC",MYSQL_ASSOC);
+ foreach ($products as $product) {
+ $retval[$product['product_id']]=$product['product_name'];
+ }
+ return $retval;
+}
+
+/**
+ * Get an priority-list of operating systems for select list.
+ * @return array $oss
+ */
+function mirror_get_products_select_priority()
+{
+ $products = db_get("SELECT product_id,product_name FROM mirror_products ORDER BY product_priority ASC",MYSQL_ASSOC);
+ foreach ($products as $product) {
+ $retval[$product['product_id']]=$product['product_name'];
+ }
+ return $retval;
+}
+
+/**
+ * Insert a new location.
+ * @param int $product
+ * @param int $os
+ * @param string $path
+ * @return bool
+ */
+function mirror_insert_location($product,$os,$path)
+{
+ return db_query("INSERT INTO mirror_locations(product_id,os_id,location_path) VALUES({$product},{$os},'{$path}')");
+}
+
+/**
+ * Update a location.
+ * @param int $location
+ * @param int $product
+ * @param int $os
+ * @param string $path
+ * @return bool
+ */
+function mirror_update_location($location,$product,$os,$path)
+{
+ return db_query("UPDATE mirror_locations SET product_id={$product},os_id={$os},location_path='{$path}' WHERE location_id={$location}");
+}
+
+/**
+ * Delete a location.
+ * @param int $id
+ * @return bool
+ */
+function mirror_delete_location($id)
+{
+ return db_query("DELETE FROM mirror_locations WHERE location_id={$id}");
+}
+
+/**
+ * Get locations.
+ * @return array $locations array containing all location information.
+ */
+function mirror_get_locations()
+{
+ return db_get("
+ SELECT
+ location_id,
+ product_name,
+ os_name,
+ location_path
+ FROM
+ mirror_locations,
+ mirror_products,
+ mirror_os
+ WHERE
+ mirror_locations.product_id = mirror_products.product_id AND
+ mirror_locations.os_id = mirror_os.os_id
+ ");
+}
+
+/**
+ * Get one location.
+ * @param int $id
+ * @return array
+ */
+function mirror_get_one_location($id)
+{
+ return db_get_one("SELECT * FROM mirror_locations WHERE location_id = {$id}");
+}
+
+/**
+ * Insert a new user.
+ * @param string $username
+ * @param string $password
+ * @param string $rpassword (re-entered password)
+ * @param string $firstname
+ * @param string $lastname
+ * @param string $email
+ * @return bool
+ */
+function mirror_insert_user($username,$password,$rpassword,$firstname,$lastname,$email)
+{
+ if ($password==$rpassword) {
+ return db_query("INSERT INTO mirror_users(username,password,user_firstname,user_lastname,user_email) VALUES('{$username}',MD5('{$password}'),'{$firstname}','{$lastname}','{$email}')");
+ } else {
+ set_error('User could not be added because passwords did not match.');
+ }
+}
+
+/**
+ * Update a user.
+ * @param int $user
+ * @param string $username
+ * @param string $password
+ * @param string $rpassword (re-entered password)
+ * @param string $firstname
+ * @param string $lastname
+ * @param string $email
+ * @return bool
+ */
+function mirror_update_user($user,$username,$password,$rpassword,$firstname,$lastname,$email)
+{
+ $query = ($password==$rpassword&&!empty($password))?"UPDATE mirror_users SET username='{$username}',password=MD5('{$password}'),user_firstname='{$firstname}',user_lastname='{$lastname}',user_email='{$email}' WHERE user_id={$user}":"UPDATE mirror_users SET username='{$username}',user_firstname='{$firstname}',user_lastname='{$lastname}',user_email='{$email}' WHERE user_id={$user}";
+ return db_query($query);
+}
+
+/**
+ * Delete a user.
+ * @param int $id
+ * @return bool
+ */
+function mirror_delete_user($id)
+{
+ return db_query("DELETE FROM mirror_users WHERE user_id={$id}");
+}
+
+/**
+ * Get users.
+ * @return array $users array containing all user information.
+ */
+function mirror_get_users()
+{
+ return db_get("SELECT * FROM mirror_users");
+}
+
+/**
+ * Get one user.
+ * @param int $id
+ * @return array
+ */
+function mirror_get_one_user($id)
+{
+ return db_get_one("SELECT * FROM mirror_users WHERE user_id = {$id}");
+}
+
+/**
+ * Enable or disable a mirror.
+ * @param int $mirror
+ * @return bool
+ */
+function mirror_toggle($mirror)
+{
+ return (db_toggle_bool('mirror_mirrors','mirror_id','mirror_active',$mirror))?true:false;
+}
+
+/**
+ * Get mirror statistics.
+ * @return array $stats
+ */
+function mirror_get_mirror_stats()
+{
+ return db_get("
+ SELECT
+ *,
+ COUNT(mirror_log.mirror_id) as count
+ FROM
+ mirror_mirrors,
+ mirror_log,
+ mirror_regions,
+ mirror_mirror_region_map
+ WHERE
+ mirror_log.mirror_id = mirror_mirrors.mirror_id AND
+ mirror_mirrors.mirror_id = mirror_mirror_region_map.mirror_id AND
+ mirror_regions.region_id = mirror_mirror_region_map.region_id
+ GROUP BY
+ mirror_log.mirror_id
+ ");
+}
+
+/**
+ * Get product statistics.
+ * @return array $stats
+ */
+function mirror_get_product_stats()
+{
+ return db_get("
+ SELECT
+ *,
+ COUNT(mirror_locations.product_id) as count
+ FROM
+ mirror_log,
+ mirror_locations,
+ mirror_products
+ WHERE
+ mirror_log.location_id = mirror_locations.location_id AND
+ mirror_locations.product_id = mirror_products.product_id
+ GROUP BY
+ mirror_locations.product_id
+ ");
+}
+?>
diff --git a/php/lib/util.php b/php/lib/util.php
new file mode 100644
index 0000000..af64fbb
--- /dev/null
+++ b/php/lib/util.php
@@ -0,0 +1,322 @@
+<?php
+/**
+ * Utility funcs.
+ * @package mirror
+ * @subpackage lib
+ */
+
+/**
+ * determine float value of now
+ * @return float value of current time in seconds
+ */
+function microtime_float()
+{
+ list($usec, $sec) = explode(" ", microtime());
+ return ((float)$usec + (float)$sec);
+}
+
+/**
+ * Add a message to SESSION['messages'] array.
+ * The $_SESSION['messages'] array stores general or success messages.
+ * @param string $str message to add (optional)
+ */
+function set_msg($str=null)
+{
+ if (!empty($str))
+ {
+ $_SESSION['messages'][]=$str;
+ }
+}
+
+/**
+ * Show messages.
+ * Iterates through $_SESSION['messages'] and displays them in a ul.
+ * @param string $class css class for message style
+ */
+function show_msg($class='msg')
+{
+ if (is_array($_SESSION['messages']) && count($_SESSION['messages']) > 0)
+ {
+ echo ($class !== NULL) ? '<div class="'.$class.'">' : '';
+ echo '<ul>';
+ foreach ($_SESSION['messages'] as $message)
+ echo '<li>'.$message.'</li>';
+ echo '</ul>';
+ echo ($class !== NULL) ? '</div>' : '';
+ $ret = count($_SESSION['messages']);
+ }
+ else
+ {
+ $ret = 0;
+ }
+ unset($_SESSION['messages']);
+ return $ret;
+}
+
+/**
+ * Add an error message to SESSION['errors'] array.
+ * The $_SESSION['errors'] array stores error messages.
+ * @param string $str message to add (optional)
+ */
+function set_error($str=null)
+{
+ if (!empty($str))
+ {
+ $_SESSION['errors'][]=$str;
+ }
+}
+
+/**
+ * Show errors messages.
+ * Iterates through $_SESSION['errors'] and displays them in a ul.
+ * @param string $class css class for message style
+ */
+function show_error($class='error')
+{
+ if (@is_array($_SESSION['errors']) && count($_SESSION['errors']) > 0)
+ {
+ echo '<div class="'.$class.'">';
+ echo '<ul>';
+ foreach ($_SESSION['errors'] as $error)
+ echo '<li>'.$error.'</li>';
+ echo '</ul>';
+ echo '</div>';
+ $ret = count($_SESSION['errors']);
+ unset($_SESSION['errors']);
+ }
+ else
+ {
+ $ret = 0;
+ }
+ return $ret;
+}
+
+/**
+ * Print out an varible enclosed by &lt;pre&gt; tags
+ * @param mixed $var the variable to print by print_r
+ */
+function debug_r(&$var)
+{
+ echo '<pre>';
+ print_r($var);
+ echo '</pre>';
+}
+
+/**
+ * Generate a random string good for passwords
+ * @param in $len the length of the password string
+ * @return string password
+ */
+function password_gen($len=6)
+{
+
+ $set = array( '0','1','2','3','4','5','6','7','8','9','a','e','i','o','u','y','b','c','d','f','g','h','j','k','l','m','n','p','q','r','s','t','v','w','x','y','z' );
+ $pw = '';
+
+ while (strlen($pw) <= $len)
+ {
+ // random alphanum
+ $char = $set[array_rand($set)];
+ $pw .= $char;
+ }
+
+ return $pw;
+}
+
+/**
+ * This recursive function empty values in an 'multi-dimensional' array.
+ * @param mixed $needle it accepts just one value or an array of values
+ * @return mixed false if an empty needle passed in, else a copy of the array with needle values replaced with empty strings
+ */
+function emptify_in_array($array, $needle)
+{
+ if ($needle == '')
+ return FALSE;
+
+ foreach ($array as $key=>$val)
+ {
+ if (is_array($val))
+ $array[$key] = emptify_in_array($val, $needle);
+ elseif (is_array($needle) && in_array($val, $needle))
+ $array[$key] = '';
+ elseif ($val === $needle)
+ $array[$key] = '';
+ }
+
+ return $array;
+}
+
+/**
+ * This function checks for the existence of a particular row in a particular table matching a value.
+ * Use this with libdb, unless you want lots of problems. :)
+ * @param string $table name of table
+ * @param string $column name of column containing value to match
+ * @param string $val value to match against database (goes in WHERE clause)
+ * @param string $extra (optional) any AND or ORDER BY or LIMIT or anything you want to add.
+ * @ret bool if a match exists, return true -- otherwise return false
+ */
+function record_exists($table,$column,$val,$extra=NULL)
+{
+ $result = db_query("SELECT * FROM {$table} WHERE {$column}='{$val}' {$extra}");
+ if ($result&&mysql_num_rows($result)>0)
+ {
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Show user tabs, based on an array.
+ * @param array $tabs array of tabs (name=>href)
+ * @param string $current name of tab to highlight
+ */
+function show_tabs($tabs,$current)
+{
+ if ( is_array($tabs) )
+ {
+ echo "\n".'<div id="tabs"><ul>';
+ foreach ( $tabs as $key=>$val )
+ {
+ if ( strtolower($key) == $current)
+ echo "\n".'<li class="active-tab"><a href="'.$val.'">'.$key.'</a></li>';
+ else
+ echo "\n".'<li><a href="'.$val.'">'.$key.'</a></li>';
+ }
+ echo "\n".'</ul></div>';
+ }
+}
+
+/**
+ * Sort a two dimensional array based on a 'column' key
+ * @param array $array the array to be sorted
+ * @param mixed $key the column key to be used for sorting, an array of keys are also acceptable
+ * @param mixed $order the order of the sort, either 'asc' (ascending) or 'desc' (descending), can also be an array (with matching array keys to the $key param)
+ * @param bool $retain_keys option to retain the original keys; default to true
+ * @param bool $case_sensitive option for a case sensitive sort; default to false
+ * @return array the original array on argument errors, the sorted array on success
+ */
+function array_order_by(&$array, $key=null, $order=null, $retain_keys=TRUE, $case_sensitive=FALSE)
+{
+ if (is_array($key) && count($key)==1)
+ {
+ $temp = each($key);
+ $key = $temp['value'];
+ $order = $order[$temp['key']];
+ unset($temp);
+ }
+
+ if (is_array($key))
+ {
+ if (!is_array($order))
+ {
+ $order = array();
+ }
+ if (count($key) > count($order))
+ {
+ $order = array_pad($order, count($key), 'asc');
+ }
+
+ // sort it according to the first key
+ $temp_sort_key = reset($key);
+ $temp_order_val = $order[key($key)];
+ $return_arr = array_order_by($array, $temp_sort_key, $temp_order_val, $retain_keys, $case_sensitive);
+
+ // set up the arrays for the 'inner', next recursion
+ $key_copy = $key;
+ $order_copy = $order;
+ unset($key_copy[key($key)]);
+ unset($order_copy[key($key)]);
+
+ // get the sorting column's value in the first row
+ $temp = current($return_arr);
+ $temp_prev_sort_val = $temp[$temp_sort_key];
+ unset($temp);
+
+ $temp_return_arr = array();
+ $temp_partial_array = array();
+
+ foreach ($return_arr as $return_arr_key=>$return_arr_val)
+ {
+ if ($return_arr_val[$temp_sort_key] == $temp_prev_sort_val)
+ {
+ $temp_partial_array[$return_arr_key] = $return_arr_val;
+ }
+ else
+ {
+ if ($retain_keys)
+ {
+ $temp_return_arr = $temp_return_arr + array_order_by($temp_partial_array, $key_copy, $order_copy, $retain_keys, $case_sensitive);
+ }
+ else
+ {
+ $temp = array_order_by($temp_partial_array, $key_copy, $order_copy, $retain_keys, $case_sensitive);
+ foreach ($temp as $temp_val)
+ {
+ $temp_return_arr[] = $temp_val;
+ }
+ unset($temp);
+ }
+ $temp_prev_sort_val = $return_arr_val[$temp_sort_key];
+ $temp_partial_array = array();
+ $temp_partial_array[$return_arr_key] = $return_arr_val;
+ }
+ }
+
+ // important! if the last n $temp_prev_sort_val has the same value, then they aren't sorted and added to the temp array
+ if (count($return_arr) > count($temp_return_arr))
+ {
+ if ($retain_keys)
+ {
+ $temp_return_arr = $temp_return_arr + array_order_by($temp_partial_array, $key_copy, $order_copy, $retain_keys, $case_sensitive);
+ }
+ else
+ {
+ $temp = array_order_by($temp_partial_array, $key_copy, $order_copy, $retain_keys, $case_sensitive);
+ foreach ($temp as $temp_val)
+ {
+ $temp_return_arr[] = $temp_val;
+ }
+ unset($temp);
+ }
+ }
+
+ return $temp_return_arr;
+ }
+
+ if (empty($array) || is_null($key))
+ return $array;
+
+ if (!array_key_exists($key, reset($array)))
+ return $array;
+
+ $order =& strtolower($order);
+ if ($order == '' || ($order != 'asc' && $order != 'desc'))
+ $order = 'asc';
+
+ // construct an array that will be used to order the keys
+ foreach($array as $row_key => $row)
+ {
+ $x[$row_key] = $row[$key];
+ }
+
+ if ($case_sensitive)
+ natsort($x);
+ else
+ natcasesort($x);
+
+ if ($order == 'desc')
+ $x =& array_reverse($x, TRUE);
+
+ // now use those keys to order the original array
+ foreach($x as $row_key => $uselessvalue)
+ {
+ if ($retain_keys)
+ $return_arr[$row_key] =& $array[$row_key];
+ else
+ $return_arr[] =& $array[$row_key];
+ }
+
+ return $return_arr;
+}
+
+?>
diff --git a/php/mozilla.js b/php/mozilla.js
new file mode 100644
index 0000000..90ae99d
--- /dev/null
+++ b/php/mozilla.js
@@ -0,0 +1,22 @@
+function getDownloadURLForLanguage(aABCD, aPlatform)
+{
+ var url = "http://download.mozilla.org/?product=firefox&os=";
+
+ switch (aPlatform) {
+ case PLATFORM_WINDOWS:
+ url += "win";
+ break;
+ case PLATFORM_LINUX:
+ url += "linux";
+ break;
+ case PLATFORM_MACOSX:
+ url += "osx";
+ if (aABCD == "ja-JP")
+ aABCD = "ja-JPM";
+ break;
+ default:
+ return "http://www.mozilla.org/products/firefox/all.html";
+ }
+
+ return url + "&lang=" + aABCD;
+}
diff --git a/php/rss/download-counts.php b/php/rss/download-counts.php
new file mode 100644
index 0000000..4559647
--- /dev/null
+++ b/php/rss/download-counts.php
@@ -0,0 +1,55 @@
+<?php
+/**
+ * RSS 2.0 feed for download counts.
+ * @package mirror
+ * @subpackage rss
+ */
+
+require_once('../cfg/config.php'); // config file
+require_once(LIB.'/db.php'); // core mysql wrappers
+
+db_connect(DBHOST,DBUSER,DBPASS); // open persistent connection to db
+db_select(DBNAME); // select db
+
+// get download counts per product
+$data = db_get("SELECT * FROM mirror_products ORDER BY product_name");
+
+// time to go at the end of each item
+$now = date('G',time());
+
+// content headers, replace Content-type if already set
+header('Content-type: text/xml', true);
+echo '<?xml version="1.0"?>'."\n\n";
+
+// doctype
+echo '<rdf:RDF'."\n";
+echo ' xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"'."\n";
+echo ' xmlns="http://purl.org/rss/1.0/">'."\n\n";
+
+// channel details
+echo '<channel rdf:about="http://bouncer.gentoo.org/rss/download-counts.php">'."\n";
+echo ' <title>Gentoo Download Counts</title>'."\n";
+echo ' <link>http://www.gentoo.org/</link>'."\n";
+echo ' <description>Gentoo product download counts pulled from Bouncer database.</description> '."\n";
+
+// item listing
+echo ' <items>'."\n";
+echo ' <rdf:Seq>'."\n";
+foreach ($data as $product) {
+ echo ' <rdf:li rdf:resource="http://bouncer.gentoo.org/?product='.$product['product_name'].'&amp;lastmod='.$now.'"/>'."\n";
+}
+echo ' </rdf:Seq>'."\n";
+echo ' </items>'."\n";
+echo '</channel>'."\n\n";
+
+// item details
+foreach ($data as $product) {
+ echo '<item rdf:about="http://bouncer.gentoo.org/?product='.$product['product_name'].'&amp;lastmod='.$now.'">'."\n";
+ echo ' <title>'.$product['product_name'].'</title>'."\n";
+ echo ' <description>'.$product['product_count'].'</description>'."\n";
+ echo ' <link>http://bouncer.gentoo.org/?product='.$product['product_name'].'&amp;lastmod='.$now.'</link>'."\n";
+ echo '</item>'."\n";
+}
+
+echo "\n".'</rdf:RDF>';
+?>