Skip to content

Instantly share code, notes, and snippets.

@jalbertbowden
Created May 30, 2019 11:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jalbertbowden/2e74b502b3464f7cf87d50ce04c5f9f6 to your computer and use it in GitHub Desktop.
Save jalbertbowden/2e74b502b3464f7cf87d50ce04c5f9f6 to your computer and use it in GitHub Desktop.
alma whatever
<?php
Class AlmaAPIClient {
const SUCCESS = "success";
const API_URL = 'https://api-na.hosted.exlibrisgroup.com/almaws/v1';
private $api_key;
public function __construct($key) {
$this->api_key = $key;
}
public function get_user($uniqueID) {
try {
$url = self::API_URL . "/users/" . $uniqueID . "?user_id_type=all_unique&view=full&expand=none&apikey=l8xxd68cc2b96dee454d8c8761cb3bbccb56";
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Accept: application/json',
'Authorization: apikey ' . $this->api_key
)
);
$result = json_decode(curl_exec($ch), true);
$returnStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if($returnStatus == 400 && isset($result["errorsExist"]))
{
return $this->parseErrorCodes($result);
}
elseif($returnStatus == 400 && $result == NULL) // TODO: I honestly don't know why it's returning NULL when given a bad API key, it should be returning an error with the code "UNAUTHORIZED".
{
return 'UNAUTHORIZED';
}
elseif($returnStatus == 200)
{
return $result;
}
}
catch (RequestException $e) {
return json_decode($e);
}
}
public function create_user($json) {
try {
$url = self::API_URL . "/users?social_authentication=false&send_pin_number_letter=false";
echo '<h1>url: ' .$url. '</h1>';
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, $json);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Accept: application/json',
'Authorization: apikey ' . $this->api_key
)
);
$result = json_decode(curl_exec($ch), true);
echo '<h1>result: ' .$result. '</h1>';
$returnStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
echo '<h1>Return status: ' .$returnStatus. '</h1>';
curl_close($ch);
if($returnStatus == 400 && isset($result["errorsExist"]))
{
return $this->parseErrorCodes($result);
}
elseif($returnStatus == 400 && $result == NULL) // TODO: I honestly don't know why it's returning NULL when given a bad API key, it should be returning an error with the code "UNAUTHORIZED".
{
return 'UNAUTHORIZED';
}
elseif($returnStatus == 200)
{
return self::SUCCESS;
}
}
catch (RequestException $e) {
return json_decode($e);
}
}
public function update_user($json, $primaryID) {
try {
$url = self::API_URL . "/users/" .$primaryID;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($ch, CURLOPT_POSTFIELDS, $json);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Accept: application/json',
'Authorization: apikey ' . $this->api_key
)
);
$result = json_decode(curl_exec($ch), true);
$returnStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if($returnStatus == 400 && isset($result["errorsExist"]))
{
return $this->parseErrorCodes($result);
}
elseif($returnStatus == 400 && $result == NULL) // TODO: I honestly don't know why it's returning NULL when given a bad API key, it should be returning an error with the code "UNAUTHORIZED".
{
return 'UNAUTHORIZED';
}
elseif($returnStatus == 200)
{
return self::SUCCESS;
}
}
catch (RequestException $e) {
return json_decode($e);
}
}
public function parseErrorCodes($result) {
$errorList = array();
$index = 0;
foreach ($result["errorList"] as $error) {
switch($error[$index]["errorCode"])
{
case "401851":
$errorList[] = "A user with that email already exists.";
break;
case "500038":
$errorList[] = "Your password must be at least 8 characters long and can't be a commonly used password.";
break;
default:
$errorList[] = "Something went wrong, please try again later! (Error Code: " . $error[$index]["errorCode"] . ")";
}
$index++;
}
return $errorList;
}
}
?>
<?php
Class ErrorList {
private static $errors;
public function get() {
return self::$errors;
}
public function set(array $newErrors) {
self::$errors = $newErrors;
}
}
?>
<?php
require 'vendor/autoload.php';
include $_SERVER["DOCUMENT_ROOT"] . '/admin/AlmaAPIClient.php';
include 'DMVDatabaseClient.php';
include 'ErrorList.php';
use Rakit\Validation\Validator;
/**
* Provides basic CSRF protection.
*
* Make sure session_start() is the first thing that gets run on the page.
*
* @return Bool
*/
function validateCSRFToken() {
session_start();
if (empty($_SESSION['token']) || empty($_SESSION['token-expire'])) {
$_SESSION['token'] = bin2hex(random_bytes(32));
$_SESSION['token-expire'] = time() + 3600; // 1 hour
}
if (time() >= $_SESSION['token-expire']) {
echo "Your session has expired, please refresh the page.";
$_SESSION['token-expire'] = null;
exit;
}
$token = $_SESSION['token'];
if (!empty($_POST['token'])) {
if (hash_equals($_SESSION['token'], $_POST['token'])) {
return true;
}
}
}
/**
* Validates the form fields.
* Sets $errorList to error array if there are errors.
* Returns true if there are no errors.
*
* @param ErrorList $errorList A object which stores an array of errors.
* @return Bool
*/
function validateForm($errorList) {
$validator = new Validator;
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$validation = $validator->validate($_POST, [
'first_name' => 'required|max:255',
'middle_name' => 'max:255',
'last_name' => 'required|max:255',
'email' => 'required|email|max:255',
'email_confirmation' => 'required|same:email',
'password' => 'required|min:8|max:255',
'password_confirmation' => 'required|same:password',
'street_address' => 'required|max:255',
'street_address2' => 'max:255',
'city' => 'required|max:255',
'state' => 'required|min:2|max:2|alpha',
'zip' => 'required|digits:5',
'DMVNumber' => 'required|max:255',
'DMVNumber_confirmation' => 'required|same:DMVNumber',
'phone' => 'max:255'
], [
'required' => ':attribute is required.',
'email' => 'You must enter a valid email address.',
'same' => ':field and :attribute must match.',
'min' => ':attribute must be at least :min characters long.',
'max' => ':attribute must be less than 256 characters.',
]);
storeOldFieldValues($_POST);
if ($validation->fails()) {
$errorList->set($validation->errors()->all(':message'));
return false;
}
else {
return true;
}
}
}
/**
* Constructs a JSON string with the values from the form.
*
* @return String
*/
function generateJSON(Array $data) {
$finalJSON = '{
"password": "' . $data['password'] . '",
"status": {
"value": "ACTIVE"
},
"record_type": {
"value": "PUBLIC"
},
"primary_id": "' . $data['email'] . '",
"first_name": "' . $data['first_name'] . '",
"middle_name": "' . $data['middle_name'] . '",
"last_name": "' . $data['last_name'] . '",
"user_group": {
"value": "01"
},
"campus_code": {
"value": "Main"
},
"preferred_language": {
"value": "en"
},
"birth_date": "1979-01-11Z",
"expiry_date": "2030-01-16Z",
"purge_date": "2021-01-20Z",
"account_type": {
"value": "INTERNAL"
},
"contact_info": {
"address": [
{
"preferred": true,
"line1": "' . $data['street_address'] . '",
"line2": "' . $data['street_address2'] . '",
"city": "' . $data['city'] . '",
"state_province": "' . $data['state'] . '",
"postal_code": "' . $data['zip'] . '",
"address_note": "",
"start_date": "2013-12-26Z",
"address_type": [
{
"value": "home"
}
]
}
],
"email": [
{
"description": null,
"preferred": true,
"email_address": "' . $data['email'] . '",
"email_type": [
{
"value": "personal"
}
]
}
]
},
"user_block": [
{
"block_type": {
"value": "GENERAL"
},
"block_description": {
"value": "02-GLOBAL"
},
"block_status": "ACTIVE"
}
]';
if(isset($data['mailingList']))
{
$finalJSON = $finalJSON . ',
"user_statistic": [
{
"statistic_category": {
"value": "NLS",
"desc": "Newsletter Subscriber"
}
}
]';
}
$finalJSON = $finalJSON . '}';
return $finalJSON;
}
/**
* Creates an AlmaAPIClient and attempts to create a user from the form data.
* Sets $errorList to error array if there are errors.
*
* @param String $json A JSON string that will be sent to the Alma API.
* @param ErrorList $errorList A object which stores an array of errors.
*/
function callAlmaAPI($json, $errorList) {
#echo '<h1>JSON: ' .$json. '</h1>';
#echo '<h1>error list: ' .print_r($errorList). '</h1>';
# echo '<h1>error list 0: ' .print_r($errorList{}). '</h1>';
# echo '<h1>error list 1: ' .print_r($errorList[1]). '</h1>';
$config = parse_ini_file($_SERVER["DOCUMENT_ROOT"] . "/admin/alma_config.ini");
echo '<h1>' .$config["api_key"]. '</h1>';
#echo '<h1>' .serialize($errorList). '</h1>';
$alma_api = new AlmaAPIClient($config["api_key"]);
#echo '<h1>' .serialize($alma_api). '</h1>';
$api_result = $alma_api->create_user($json);
echo '<h1>get type: ' .gettype($api_result). '</h1>';
if(is_null($api_result)){
echo '<h1>is_null true</h1>';
$api_result[0] = 'UNAUTHORIZED';
echo '<h1>new api result val: ' .$api_result[0]. '</h1>';
} else {
echo '<h1>is_null not true</h1>';
}
#echo '<h1>type: ' .gettype($api_result). '</h1>';
if($api_result == AlmaAPIClient::SUCCESS) {
return true;
}
else {
# var_dump(isset($errorList));
$api_result[0] = 'UNAUTHORIZED';
$errorList->set($api_result);
return false;
}
}
/**
* Verifies the client's reCaptcha request.
*
* @param Bool
*/
function verifyRecaptcha() {
$postdata = http_build_query(["secret" => "6LfHhg4UAAAAAIZWwuoDu2Es4WLakCp_M3EwQ3t6", "response" => $_POST['g-recaptcha-response'], "remoteip" => $_SERVER['REMOTE_ADDR']]);
$options = ['http' =>
[
'method' => 'POST',
'header' => 'Content-type: application/x-www-form-urlencoded',
'content' => $postdata
]
];
$context = stream_context_create($options);
$googresp = file_get_contents('https://www.google.com/recaptcha/api/siteverify', false, $context);
$decgoogresp = json_decode($googresp);
return $decgoogresp->success;
}
/**
* Stores an array of values into the $_SESSION
*
* @param Array $values
*/
function storeOldFieldValues($values) {
unset($_SESSION['old']);
foreach($values as $field=>$value) {
$_SESSION['old'][$field] = $value;
}
// We don't need to store the CSRF token or the reCaptcha token in the session
unset($_SESSION['old']['token']);
unset($_SESSION['old']['g-recaptcha-response']);
}
/**
* Get the previously submitted value to repopulate the field.
*
* @param String
*/
function old($field) {
if(isset($_SESSION['old']) && isset($_SESSION['old'][$field]) && $_SERVER['REQUEST_METHOD'] === 'POST')
{
return htmlentities($_SESSION['old'][$field]);
}
else {
if(isset($_SESSION['old']) && isset($_SESSION['old'][$field]))
unset($_SESSION['old'][$field]); // If it's a GET request, get rid of the session variables
return '';
}
}
$errorList = new ErrorList;
if(validateCSRFToken() && verifyRecaptcha()) {
if(validateForm($errorList)){
if(callAlmaAPI(generateJSON($_POST), $errorList)){
$dmv_db = new DMVDatabaseClient();
if($dmv_db->db_create_patron($_POST)) {
header('Location: https://' . $_SERVER['HTTP_HOST'] . '/register/success.php');
}
}
}
}
?>
<html lang="en">
<head>
<meta name="robots" content="noindex">
<meta name="googlebot" content="noindex">
<title>Library of Virginia Account Registration</title>
<link rel="stylesheet" type="text/css" href="style.css">
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
</head>
<body>
<div class="content">
<section class="section section--quarter">
<div class="section__background"></div>
<div class="logo-wrapper">
<a href="/"><img class="logo" src="/img/logo.svg"></a>
</div>
<div class="infoBox">
<p class="infoBox__text">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras dignissim luctus nibh. Integer placerat metus pharetra nibh pharetra, vel viverra nulla efficitur. Etiam interdum dictum lorem at facilisis. Donec dapibus at sapien nec blandit. Proin viverra est ut turpis tincidunt sodales. Quisque suscipit orci ut nulla rutrum sagittis. Quisque nisl neque, finibus sit amet porta eget, rutrum vel quam. Aenean porta tincidunt scelerisque. Pellentesque varius lectus id nunc ullamcorper, vel lobortis augue ultrices. Etiam tincidunt consectetur est eget semper. Proin a eleifend mauris, sed rutrum purus.
</p>
<div class="infoBox__text">
Cras dignissim luctus nibh.
</div>
</div>
</section>
<section class="section section--threequarter">
<div class="header">
<h2 class="header__title">New Patron Registration</h2>
</div>
<?php
if(count($errorList->get())) {
?>
<div class="errorList-wrapper" role="alert">
<ul class="errorList">
<?php
foreach ($errorList->get() as $error) {
?>
<li class="error"><?= ucfirst($error) ?></li>
<?php
}
?>
</ul>
</div>
<?php
}
?>
<form method="POST" action="">
<input type="hidden" name="token" value="<?= $_SESSION['token'] ?>"/>
<section class="form__section form__section--orange">
<div class="form__fieldset">
<legend class="fieldset__legend">
<h3 class="legend__heading">
Library Account Information
</h3>
</legend>
<section class="fieldset__content">
<div class="form__group">
<div class="form__group form__group--threequarter">
<label class="form__label" for="email_field">
Email
</label>
<input id="email_field" class='form__input' name="email" type="text" value="<?= old('email') ?>" required />
</div>
<div class="form__group form__group--threequarter">
<label class="form__label" for="emailConfirmation_field">
Email Confirmation
</label>
<input id="emailConfirmation_field" class='form__input' name="email_confirmation" type="text" value="<?= old('email_confirmation') ?>" required />
</div>
</div>
<div class="form__group form__group--singleLine">
<div class="form__group form__group--half">
<label class="form__label" for="password_field">
Password
</label>
<input id="password_field" class='form__input' name="password" type="password" required />
</div>
<div class="form__group form__group--half">
<label class="form__label" for="passwordConfirmation_field">
Password Confirmation
</label>
<input id="passwordConfirmation_field" class='form__input' name="password_confirmation" type="password" required />
</div>
</div>
<div class="form__group form__group--singleLine">
<div class="form__group form__group--half">
<label class="form__label" for="DMVNumber_field">
DMV Customer ID
</label>
<input id="DMVNumber_field" class='form__input' name="DMVNumber" type="text" value="<?= old('DMVNumber') ?>" required />
</div>
<div class="form__group form__group--half">
<label class="form__label" for="DMVNumberConfirmation_field">
DMV Customer ID Confirmation
</label>
<input id="DMVNumberConfirmation_field" class='form__input' name="DMVNumber_confirmation" type="text" value="<?= old('DMVNumber_confirmation') ?>" required />
</div>
</div>
</section>
</div>
</section>
<section class="form__section form__section--blue">
<div class="form__fieldset">
<legend class="fieldset__legend">
<h3 class="legend__heading">
Patron Name
</h3>
</legend>
<section class="fieldset__content">
<div class="form__group form__group--singleLine">
<div class="form__group form__group--third">
<label class="form__label" for="firstName_field">
First Name
</label>
<input id="firstName_field" class='form__input' name="first_name" type='text' value="<?= old('first_name') ?>" required />
</div>
<div class="form__group form__group--third">
<label class="form__label" for="middleName_field">
Middle Name <span class='form__optional'>(Optional)</span>
</label>
<input id="middleName_field" class='form__input' name="middle_name" type='text' value="<?= old('middle_name') ?>" />
</div>
<div class="form__group form__group--third">
<label class="form__label" for="lastName_field">
Last Name
</label>
<input id="lastName_field" class="form__input" name="last_name" type="text" value="<?= old('last_name') ?>" required />
</div>
</div>
</section>
</div>
</section>
<section class="form__section form__section--red">
<div class="form__fieldset">
<legend class="fieldset__legend">
<h3 class="legend__heading">
Contact Information
</h3>
</legend>
<section class="fieldset__content">
<div class="form__group">
<label class="form__label" for="streetAddress_field">
Street Address
</label>
<input class="form__input" id="streetAddress_field" name="street_address" type="text" value="<?= old('street_address') ?>" required />
</div>
<div class="form__group">
<label class="form__label" for="streetAddress2_field">
Street Address Line 2 <span class='form__optional'>(Optional)</span>
</label>
<input class="form__input" id="streetAddress2_field" name="street_address2" type="text" value="<?= old('street_address2') ?>" />
</div>
<div class="form__group form__group--singleLine">
<div class="form__group form__group--third">
<label class="form__label" for="city_field">
City
</label>
<input class="form__input" id="city_field" name="city" type="text" value="<?= old('city') ?>" required />
</div>
<div class="form__group form__group--third">
<label class="form__label" for="state_field">
State
</label>
<input class="form__input" id="state_field" name="state" type="text" maxlength="2" value="<?= old('state') ?>" required />
</div>
<div class="form__group form__group--third">
<label class="form__label" for="zip_field">
Zip
</label>
<input class="form__input" id="zip_field" name="zip" type="text" value="<?= old('zip') ?>" required />
</div>
</div>
<div class="form__group form__group--singleLine">
<div class="form__group form__group--third">
<label class="form__label" for="phone_field">
Phone Number
</label>
<input id="phone_field" class='form__input' name="phone" type='tel' value="<?= old('phone') ?>" required />
</div>
</div>
</section>
</div>
</section>
<section class="form__section form__section--purple">
<div class="form__fieldset">
<legend class="fieldset__legend">
<h3 class="legend__heading">
A few more things...
</h3>
</legend>
<section class="fieldset__content">
<div class="checkbox__item-wrapper">
<div class="checkbox__item">
<input class="form__input--checkbox" id="mailingList_checkbox" type="checkbox" name="mailingList" <?= old('mailingList') ? 'checked' : ''; ?> />
<label class="form__label--checkbox" for="mailingList_checkbox">
I'd like to be signed up for the Library of Virginia Foundation mailing list.
</label>
</div>
</div>
<div class="checkbox__item-wrapper">
<div class="g-recaptcha" data-sitekey="6LfHhg4UAAAAAF1erABlIyHvL0LChHg3pTg_jlGk" data-theme="dark"></div>
</div>
<div class="button-wrapper">
<button class="button" type="submit">Register</button>
</div>
</section>
</div>
</section>
</form>
</section>
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment