function get_config() {
return [
'site_root' => '/',
- 'title_append' => 'DEV SITE',
+ 'title_append' => '',
+ ];
+}
+
+function get_db_details() {
+ return [
+ 'host' => 'localhost',
+ 'database' => 'DB',
+ 'user' => 'USER',
+ 'password' => "PASSWORD",
];
}
clear: both;
}
+.error {
+ color: red;
+}
+
/* General styling for tables. */
table {
/* Centre tables. */
--- /dev/null
+div.field {
+ display: block;
+ margin: 1em 0;
+}
+
+div.field label {
+ font-weight: bold;
+ display: block;
+}
+
+div.field.required label::before {
+ content: '*';
+ color: red;
+}
--- /dev/null
+<?php
+require_once('includes/config.php');
+
+function db_connect() {
+ global $db_conn;
+ if (!$db_conn) {
+ $db = get_db_details();
+ $db_conn = new mysqli($db['host'], $db['user'], $db['password'], $db['database']);
+ if ($db_conn->connect_error)
+ die('Database connection failed: ' . $db_conn->connect_error);
+ }
+}
+
+function run_sql($sql) {
+ global $db_conn;
+ if (!$db_conn) db_connect();
+ $result = $db_conn->query($sql);
+ if ($result === false) {
+ error_log('Error executing SQL query: ' . $db_conn->error
+ . ' while running the SQL: ' . $sql);
+ die('Database query failed! Error: ' . $db_conn->error);
+ }
+ return $result;
+}
+
+function escape_mysql_string($string) {
+ global $db_conn;
+ if (!$db_conn) db_connect();
+ return $db_conn->real_escape_string($string);
+}
+
+function mysql_quote_value($value) {
+ if (is_null($value)) return 'NULL';
+ return sprintf("'%s'", escape_mysql_string($value));
+}
+
+function simple_where($key, $value, $comp='=') {
+ return sprintf("%s $comp %s", $key, mysql_quote_value($value));
+}
+
+function record_exists($table, $where) {
+ $sql = "SELECT EXISTS(SELECT * FROM $table WHERE $where)";
+ $result = run_sql($sql);
+ $val = mysqli_fetch_row($result)[0];
+ if ($val) return true;
+ return false;
+}
+
+function insert_array($table, $fields) {
+ $keys = $values = [];
+ foreach ($fields as $key=>$value) {
+ $keys[] = $key;
+ $values[] = mysql_quote_value($value);
+ }
+ $sql = "INSERT INTO $table (" . implode(',', $keys) . ') '
+ . 'VALUES (' . implode(',', $values) . ')';
+ return run_sql($sql);
+}
--- /dev/null
+<?php
+require_once('includes/utils.php');
+
+
+// TODO: Currently trivial, but we will want to handle more complicated cases
+// later.
+function get_sent_field_value($values, $name) {
+ if (!empty($values[$name])) return $values[$name];
+ return '';
+}
+function get_field_id($name) {
+ return $name;
+}
+
+function general_bare_field($type, $values, $name, $attrs=[]) {
+ $value = get_sent_field_value($values, $name);
+ $id = get_field_id($name);?>
+
+ <input type="<?php esc($type);?>" name="<?php esc($name);?>"
+ id="<?php esc($id);?>" value="<?php esc($value);?>"<?php
+ foreach($attrs as $name=>$value) esc("$name=\"$value\" ");?>
+ /><?php
+}
+
+function field_label($name, $label) {
+ $id = get_field_id($name);?>
+ <label for="<?php esc($id);?>"><?php esc($label);?></label><?php
+}
+
+function general_field($type, $values, $name, $label, $attrs=[]) {?>
+ <div class="field<?php esc(array_key_exists('required', $attrs) ? ' required'
+ : '');?>"><?php
+ field_label($name, $label);
+ general_bare_field($type, $values, $name, $attrs);?>
+ </div><?php
+}
+
+function text_field($values, $name, $label, $attrs=[]) {
+ general_field('text', $values, $name, $label, $attrs);
+}
+
+function email_field($values, $name, $label, $attrs=[]) {
+ general_field('email', $values, $name, $label, $attrs);
+}
+
+function hidden_field($name, $value) {
+ general_bare_field('hidden', [$name=>$value], $name);
+}
+?>
--- /dev/null
+<?php
+require_once('includes/utils.php');
+
+function require_field(&$errors, $data, $key, $name=null) {
+ if (is_null($name)) $name = key_to_human_text($key);
+
+ if (empty($data[$key])) $errors[] = "The $name field must be filled in.";
+ return empty($errors);
+}
+
+/**
+* Validate an email address.
+* Provide email address (raw input)
+* Returns true if the email address has the email
+* address format and the domain exists.
+*
+* Adapted from https://www.linuxjournal.com/article/9585
+*/
+function validate_email_address(&$errors, $email) {
+ $isValid = true;
+ $atIndex = strrpos($email, "@");
+ if (is_bool($atIndex) && !$atIndex) {
+ $errors[] = "Missing '@' symbol in email address.";
+ return false;
+ }
+ $domain = substr($email, $atIndex+1);
+ $local = substr($email, 0, $atIndex);
+
+ $localLen = strlen($local);
+ if ($localLen < 1 || $localLen > 64) {
+ $errors[] = 'Invalid length for local part of email address.';
+ return false;
+ }
+ $domainLen = strlen($domain);
+ if ($domainLen < 1 || $domainLen > 255) {
+ $errors[] = 'Invalid length for domain part of email address.';
+ return false;
+ }
+
+ if ($local[0] == '.' || $local[$localLen-1] == '.'
+ || preg_match('/\\.\\./', $local)) {
+ $errors[] = 'Invalid format for local part of email address.';
+ return false;
+ }
+
+ if (!preg_match('/^[A-Za-z0-9\\-\\.]+$/', $domain)) {
+ $errors[] = 'Invalid character in domain part of email address.';
+ return false;
+ }
+
+ if (preg_match('/\\.\\./', $domain)) {
+ $errors[] = 'Invalid format for domain part of email address.';
+ return false;
+ }
+
+ if (!preg_match('/^(\\\\.|[A-Za-z0-9!#%&`_=\\/$\'*+?^{}|~.-])+$/',
+ str_replace("\\\\","",$local))
+ && !preg_match('/^"(\\\\"|[^"])+"$/', str_replace("\\\\","",$local))) {
+ $errors[] = 'Invalid character(s) in local part of email address - please '
+ . 'enclose in quotation marks.';
+ return false;
+ }
+
+ if (!(checkdnsrr($domain,"MX") || checkdnsrr($domain,"A"))) {
+ $errors[] = 'Email address domain has no relevant DNS records.';
+ return false;
+ }
+ return true;
+}
/*
'about' => [ 'name' => 'About',
'path' => '#'
- ],
+ ],*/
'join' => [ 'name' => 'Join',
- 'path' => '#'
- ],
+ 'path' => 'join.php'
+ ],/*
'links' => [ 'name' => 'Useful Links',
'path' => '#'
],
$modified = date('Ymd-His', filemtime($doc_root . $site_root . $path));
return "?v=$modified";
}
+
+function show_error_list($errors) {
+ if (empty($errors)) return;?>
+ <div class="error"><?php
+ foreach ($errors as $error) {?><p><?php esc($error);?></p><?php }?>
+ </div><?php
+}
+
+function key_to_human_text($key) {
+ return ucfirst(str_replace('_', ' ', $key));
+}
--- /dev/null
+<?php
+require_once('includes/utils.php');
+require_once('includes/html-templating.php');
+require_once('includes/navbar.php');
+require_once('includes/fields.php');
+require_once('includes/form-validation.php');
+require_once('includes/database.php');
+
+function validate_member_data(&$errors, $data) {
+ foreach (['first_name', 'surname', 'email_address'] as $field)
+ require_field($errors, $data, $field);
+
+ if (empty($errors)) {
+ validate_email_address($errors, $data['email_address']);
+ //TODO: will want to turn this back on in the future.
+ /*if (record_exists('members', simple_where('email_address', $data['email_address'])))
+ $errors[] = 'Email address has already been used.';*/
+ }
+
+ return empty($errors);
+}
+
+function confirm_sent_data($data) {?>
+ <form method="post" action="">
+ <table style="width: max-content;"><?php
+ foreach (['first_name', 'surname', 'email_address', 'address_line_1',
+ 'address_line_2', 'city', 'region', 'postcode', 'country']
+ as $key) {
+ if (!empty($data[$key])) {?>
+ <tr>
+ <th><?php esc(key_to_human_text($key));?>:</th>
+ <td><?php esc($data[$key]);?></td>
+ </tr><?php
+ hidden_field($key, $data[$key]);
+ }
+ }?>
+ </table>
+ <input type="submit" name="back" value="Back" />
+ <input type="submit" name="paypal" value="Pay for membership now via PayPal" />
+ <input type="submit" name="other-payment" value="Pay for membership later using another payment method" />
+ </form><?php
+}
+
+function store_member_data($data) {
+ $fields['date_added'] = date('Y-m-d H:i:s');
+ foreach (['first_name', 'surname', 'email_address', 'address_line_1',
+ 'address_line_2', 'city', 'region', 'postcode', 'country', 'paypal_attempt']
+ as $key)
+ if (!empty($data[$key])) $fields[$key] = $data[$key];
+
+ insert_array('members', $fields);
+}
+
+function additional_stylesheets() {
+ stylesheet('fields');
+}
+
+function content() {?>
+ <h1>Join the YCRA</h1>
+ <?php
+ if (array_key_exists('paypal-cancel', $_GET)) {?>
+ <p>Your PayPal payment has been cancelled and you will not be charged..</p><?php
+ return;
+ }
+ if (array_key_exists('paypal-paid', $_GET)) {?>
+ <p>Thank you for paying for your YCRA membership via PayPal. Congratulations
+ on becoming a YCRA member!</p><?php
+ return;
+ }
+ $errors = $params = [];
+
+ if (array_key_exists('back', $_POST))
+ $params = $_POST;
+ else if (array_key_exists('join', $_POST)) {
+ if (validate_member_data($errors, $_POST)) {?>
+ <p>Please check that the information you entered (as shown below) is
+ correct.</p><?php
+
+ confirm_sent_data($_POST);
+ return;
+ }
+ else $params = $_POST;
+ }
+ else if (array_key_exists('paypal', $_POST)) {
+ if (validate_member_data($errors, $_POST))
+ $errors[] = 'Error occurred redirecting to PayPal. Please try again.';
+ $params = $_POST;
+ }
+ else if (array_key_exists('other-payment', $_POST)) {
+ if (validate_member_data($errors, $_POST)) {
+ store_member_data($_POST);?>
+ <p>We have received your data. You will become a member of the YCRA after
+ you have paid the membership fee.</p><?php
+ return;
+ }
+ else $params = $_POST;
+ }?>
+
+ <p>Please use the form below to either join the YCRA, or express interest in
+ joining the YCRA.</p>
+
+ <p>You will become a member of the YCRA if you enter your details below and
+ then subsequently pay for membership.</p>
+
+ <p>Please view our <a <?php href('privacy-policy.php');?>>privacy policy</a>
+ for information on how we will process your data.</p>
+
+ <?php show_error_list($errors);?>
+
+ <form method="post" action=""><?php
+ text_field($params, 'first_name', 'First name', ['required'=>'']);
+ text_field($params, 'surname', 'Surname', ['required'=>'']);
+ email_field($params, 'email_address', 'Email address', ['required'=>'']);?>
+
+ <p>When you join the YCRA, we will send you a membership pack. If you do
+ <b>not</b> pay for your membership via PayPal, we will need your address.
+ Please either enter it here, or provide it when you pay for your
+ membership.</p><?php
+
+ text_field($params, 'address_line_1', 'Address line 1');
+ text_field($params, 'address_line_2', 'Address line 2');
+ text_field($params, 'city', 'City');
+ text_field($params, 'region', 'Region');
+ text_field($params, 'postcode', 'Postcode');
+ text_field($params, 'country', 'Country');?>
+
+ <input type="submit" name="join" value="Join" />
+ </form>
+
+ <?php
+}
+
+
+if (array_key_exists('paypal', $_POST)) {
+ if (validate_member_data($errors, $_POST)) {
+ store_member_data(array_merge($_POST, ['paypal_attempt'=>1]));
+ $fields = [ 'cmd' => '_cart',
+ 'business' => 'treasurer@ycra.org.uk',
+ 'upload' => '1',
+ 'currency_code' => 'GBP',
+ 'item_name_1' => 'One year YCRA membership',
+ 'item_number_1' => 'YCRA-MEM-1',
+ 'quantity_1' => 1,
+ 'amount_1' => 15,
+ 'no_shipping' => 2,
+ 'no_note' => 1,
+ 'cancel_return' => 'https://ycra.org.uk/join.php?paypal-cancel=1',
+ 'return' => 'https://ycra.org.uk/join.php?paypal-paid=1',
+ ];
+ $url_fields = [];
+ foreach ($fields as $field=>$value)
+ $url_fields[] = urlencode($field) . '=' . urlencode($value);
+
+ $url = 'https://www.paypal.com/cgi-bin/webscr?' . implode('&', $url_fields);
+ header("Location: $url");
+ return;
+ }
+}
+
+require_once('includes/template.php');
+?>