}
# Paint the html constructs that form the widget, inside the body
function paint_widget() {
global $SCRIPT_NAME;
$loans = $this->library_loans;
?>
if ( $loans->logged_in ) { ?>
Currently = sizeof($loans->holds) ?> item= $this->pluralize($loans->holds) ?> on hold
foreach ($loans->holds as $item) { ?>
if ( $item['status'] == $loans->yours_text ) echo '
' ?>
= $item['status'] ?> = $item['due'] ?>
—= $item['pickup'] ?>
if ( $item['status'] == $loans->yours_text ) echo '
' ?>
} ?>
Currently = sizeof($loans->items) ?> item= $this->pluralize($loans->items) ?> borrowed
foreach ($loans->items as $item) { ?>
Due = $item['due_nice'] ?>
—= $item['call'] ?>
} ?>
} ?>
}
# Returns 's' if $subject isn't 1 large
function pluralize( $subject ) {
if ( sizeof($subject) != 1 ) return 's';
}
}
#####
## Logic and control for dealing with the UWA Library Loans system
class UWALibraryLoans {
# Base of the library's loan query application
var $query_base = 'https://catalogue.library.uwa.edu.au/patroninfo/';
# Some magic numbers, including avoiding the y2.1k bug, early...
var $century_prefix = '20';
var $chopped_title_length = '32';
var $ready_regex = '|Ready|';
var $bad_login_regex = '|Unable to identify you|';
var $yours_text = 'Yours until';
var $due_text = 'Due';
# Internal staff/student number and barcode
var $uwa_number = '';
var $uwa_barcode = '';
# External (full) name and barcode number
var $ext_name = '';
var $ext_barcode = '';
# Patron number used by the library system
var $patron_id = 0;
# Human readable title for the uwa_number (etc) used
var $user_description;
# Arrays of loaned out items, and held items
var $items = array();
var $holds = array();
# Resource handle for the client url library
var $curl_handle = null;
# Are we Go to paint the view? Then this instance variable should ring true!
var $logged_in = false;
# Load in credentials, if they're provided
function UWALibraryLoans($credentials) {
foreach ( $credentials as $cred => $value ) {
switch ($cred) {
case 'uwa_number':
$this->uwa_number = $value;
break;
case 'uwa_barcode':
$this->uwa_barcode = $value;
break;
case 'ext_name':
$this->ext_name = $value;
break;
case 'ext_barcode':
$this->ext_barcode = $value;
break;
case 'user_description':
$this->user_description = $value;
break;
}#end switch $cred
}#end foreach $credentials
if ( $this->sufficient_credentials() ) {
$this->get_patron_id();
$this->get_loan_info();
}
}
# Return true only if a card id and barcode pair exist,
# and clear the other possible credentials for disambiguation
function sufficient_credentials() {
if ( $this->uwa_number && $this->uwa_barcode ) {
$this->ext_name = $this->ext_barcode = '';
return true;
}
else if ( $this->ext_name && $this->ext_barcode ) {
$this->uwa_number = $this->uwa_barcode = '';
return true;
}
else return false;
}
# Gets the patron id used by the library in urls
function get_patron_id() {
$ch = $this->init_curl();
$login_response = curl_exec($ch);
preg_match('|patroninfo/(\d+)/|', $login_response, $this->patron_id);
$this->patron_id = $this->patron_id[1];
}
# Initialized the curl state, so at a minimum we just need to curl_exec()
# Alternatively, we can still set some opts.
function init_curl() {
if ( $this->curl_handle ) return $this->curl_handle;
$ch = curl_init($this->query_base);
$post_data = array();
$post_data['extpatid'] = $this->uwa_number;
$post_data['extpatpw'] = $this->uwa_barcode;
$post_data['name'] = $this->ext_name;
$post_data['code'] = $this->ext_barcode;
$post_data['submit'] = "SUBMIT";
foreach ($post_data as $name => $value) {
$post .= "$name=" .urlencode(utf8_encode($value)). "&";
}
$post = substr($post,0,-1);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, trim($post));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, false);
$this->curl_handle = $ch;
return $ch;
}
# Just retrieve both sides of the loan information
function get_loan_info() {
$this->get_items();
$this->get_holds();
}
# Get borrowed items, which is subtly different in many ways to get_holds()
function get_items() {
$ch = $this->init_curl();
curl_setopt($ch, CURLOPT_URL, $this->query_base.$this->patron_id.'/items');
$item_response = curl_exec($ch);
# Verify good login
if ( !$this->logged_in ) {
if ( !$this->verify_login($item_response) ) return;
}
# Get all the items on the page by id
preg_match_all( '|"item&(\d+)"|', $item_response, $item_ids );
$item_ids = $item_ids[1];
# Get the names of all the items
preg_match_all( '|replace_or_redraw[^>]+item&\d+[^>]*>\s([^<]*)\s<|', $item_response, $item_names );
$item_names = $item_names[1];
for ( $i = 0; $i < sizeof($item_names); $i++ )
if ( strlen($item_names[$i]) == $this->chopped_title_length )
$item_names[$i] = $item_names[$i] . '…';
# Get the due dates of all the items
preg_match_all( '|patFuncStatus">[^<]*(\d\d-\d\d-\d\d\s?[^\s]*)[^<]*<|', $item_response, $item_due_dates );
$item_due_dates = $item_due_dates[1];
$item_due_dates = preg_replace( '|(\d\d)-(\d\d)-(\d\d)(.*$)|', '\3-\2-\1\4', $item_due_dates); # Reverse date format
# Get the call numbers of all the items
preg_match_all( '|patFuncCallNo">\s*([^<]*)\s*<|', $item_response, $item_call_nos );
$item_call_nos = $item_call_nos[1];
# Stick all our information into the 'items' instance variable
for ( $i = 0; $i < sizeof($item_ids); $i++ ) {
$this->items[] = array(
'id' => $item_ids[$i],
'name' => $item_names[$i],
'due' => $item_due_dates[$i],
'call' => $item_call_nos[$i] );
}
# Sort items by due date then title
usort($this->items, 'cmp_items');
# Make nice date strings, where possible
$this->expound_dates($this->items, 'due');
}
# Get items on hold, which is subtly different in many ways to get_items()
function get_holds() {
$ch = $this->init_curl();
curl_setopt($ch, CURLOPT_URL, $this->query_base.$this->patron_id.'/holds');
$holds_response = curl_exec($ch);
# Verify good login
if ( !$this->logged_in ) {
if ( !$this->verify_login($holds_response) ) return;
}
# Get all of the items on the page by id
preg_match_all( '|"item&(\d+)"|', $holds_response, $item_ids );
$item_ids = $item_ids[1];
# Get the names of all the items
preg_match_all( '|replace_or_redraw[^>]+item&\d+[^>]*>\s([^<]*)\s<|', $holds_response, $item_names );
$item_names = $item_names[1];
for ( $i = 0; $i < sizeof($item_names); $i++ )
if ( strlen($item_names[$i]) == $this->chopped_title_length )
$item_names[$i] = $item_names[$i] . '…';
# Get the due dates of all the items
preg_match_all( '|patFuncStatus">\s*([^<]*)\s*<|', $holds_response, $item_due_dates );
$item_due_dates = $item_due_dates[1];
for ( $i = 0; $i < sizeof($item_due_dates); $i++ ) {
# Is it ready for us to pick up?
$item_status[] = preg_match($this->ready_regex, $item_due_dates[$i]) ? $this->yours_text : $this->due_text;
# Make the date nice
if ( preg_match('|\d\d-\d\d-\d\d|', $item_due_dates[$i]) )
$item_due_dates[$i] = preg_replace('|^.*(\d\d)-(\d\d)-(\d\d).*$|', '\3-\2-\1', $item_due_dates[$i]);
}
# Get the pickup locations for all items
preg_match_all( '|patFuncPickup">\s*([^<]*)\s*<|', $holds_response, $item_call_nos );
$item_locations = $item_call_nos[1];
# Stick all our information into the 'items' instance variable
for ( $i = 0; $i < sizeof($item_ids); $i++ ) {
$this->holds[] = array(
'id' => $item_ids[$i],
'name' => $item_names[$i],
'due' => $item_due_dates[$i],
'pickup' => $item_locations[$i],
'status' => $item_status[$i] );
}
# Soft items by due date then title
usort($this->holds, 'cmp_holds');
# Make nice date strings, where possible
$this->expound_dates($this->holds, 'due');
}
# Checks for an 'unable to identify you' message, and
# sets $this->logged_in if all is good (and returns true.)
function verify_login($page) {
if ( preg_match($this->bad_login_regex, $page) ) {
$this->logged_in = false;
return false;
}
else {
$this->logged_in = true;
return true;
}
}
# Takes an item array with a 'yy-mm-dd' formatted date key, and
# adds keys with a nicely formatted date and literal (ctime) timestamp
function expound_dates( &$items, $dkey ) {
for ( $i = 0; $i < sizeof($items); $i++ ) {
$item = &$items[$i];
if ( preg_match('|\d\d-\d\d-\d\d|', $item[$dkey]) ) {
$timestamp = strtotime( $this->century_prefix.$item[$dkey] );
$item[$dkey.'_timestamp'] = $timestamp;
$item[$dkey.'_nice'] = date('j M, y' , $timestamp);
}
else $item[$dkey.'_nice'] = $item['due'];
}
}
}#end class UWALibraryLoans
###
## Comparison function for items, to sort descending by due date, ascending by name
function cmp_items($a, $b) {
if ( strpos($a['due'],':') ) return 1;
if ( strcmp($a['due'], $b['due']) ) return strcmp($a['due'], $b['due']);
else return strcmp($a['name'], $b['name']);
}
function cmp_holds($a, $b) {
return strcmp($a['name'], $b['name']);
}
?>