ajout simpleCalDAV pour insérer les date des ateliers dans Nextcloud
This commit is contained in:
parent
152cda4234
commit
3d2377d651
|
@ -0,0 +1,106 @@
|
|||
<?php
|
||||
/**
|
||||
* CalDAVCalendar
|
||||
*
|
||||
* Copyright 2014 Michael Palm <palm.michael@gmx.de>
|
||||
*
|
||||
* This class represents an accsessible calendar on the server.
|
||||
*
|
||||
* I think the functions
|
||||
* - getURL()
|
||||
* - getDisplayName()
|
||||
* - getCalendarID()
|
||||
* - getRGBAcolor()
|
||||
* - getRBGcolor()
|
||||
* are pretty self-explanatory.
|
||||
*
|
||||
*
|
||||
* getCTag() returns the ctag of the calendar.
|
||||
* The ctag is an hash-value used to check, if the client is up to date. The ctag changes everytime
|
||||
* someone changes something in the calendar. So, to check if anything happend since your last visit:
|
||||
* just compare the ctags.
|
||||
*
|
||||
* getOrder() returns the order of the calendar in the list of calendars
|
||||
*
|
||||
*
|
||||
* @package simpleCalDAV
|
||||
*
|
||||
*/
|
||||
|
||||
class CalDAVCalendar {
|
||||
private $url;
|
||||
private $displayname;
|
||||
private $ctag;
|
||||
private $calendar_id;
|
||||
private $rgba_color;
|
||||
private $rbg_color;
|
||||
private $order;
|
||||
|
||||
function __construct ( $url, $displayname = null, $ctag = null, $calendar_id = null, $rbg_color = null, $order = null ) {
|
||||
$this->url = $url;
|
||||
$this->displayname = $displayname;
|
||||
$this->ctag = $ctag;
|
||||
$this->calendar_id = $calendar_id;
|
||||
$this->rbg_color = $rbg_color;
|
||||
$this->order = $order;
|
||||
}
|
||||
|
||||
function __toString () {
|
||||
return( '(URL: '.$this->url.' Ctag: '.$this->ctag.' Displayname: '.$this->displayname .')'. "\n" );
|
||||
}
|
||||
|
||||
// Getters
|
||||
|
||||
function getURL () {
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
function getDisplayName () {
|
||||
return $this->displayname;
|
||||
}
|
||||
|
||||
function getCTag () {
|
||||
return $this->ctag;
|
||||
}
|
||||
|
||||
function getCalendarID () {
|
||||
return $this->calendar_id;
|
||||
}
|
||||
|
||||
function getRBGcolor () {
|
||||
return $this->rbg_color;
|
||||
}
|
||||
|
||||
function getOrder () {
|
||||
return $this->order;
|
||||
}
|
||||
|
||||
|
||||
// Setters
|
||||
|
||||
function setURL ( $url ) {
|
||||
$this->url = $url;
|
||||
}
|
||||
|
||||
function setDisplayName ( $displayname ) {
|
||||
$this->displayname = $displayname;
|
||||
}
|
||||
|
||||
function setCtag ( $ctag ) {
|
||||
$this->ctag = $ctag;
|
||||
}
|
||||
|
||||
function setCalendarID ( $calendar_id ) {
|
||||
$this->calendar_id = $calendar_id;
|
||||
}
|
||||
|
||||
function setRBGcolor ( $rbg_color ) {
|
||||
$this->rbg_color = $rbg_color;
|
||||
}
|
||||
|
||||
function setOrder ( $order ) {
|
||||
$this->order = $order;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,93 @@
|
|||
<?php
|
||||
/**
|
||||
* CalDAVException
|
||||
*
|
||||
* Copyright 2014 Michael Palm <palm.michael@gmx.de>
|
||||
*
|
||||
* This class is an extension to the Exception-class, to store and report additional data in the case
|
||||
* of a problem.
|
||||
* For debugging purposes, just sorround all of your SimpleCalDAVClient-Code with try { ... } catch (Exception $e) { echo $e->__toString(); }
|
||||
*
|
||||
* @package simpleCalDAV
|
||||
*
|
||||
*/
|
||||
|
||||
class CalDAVException extends Exception {
|
||||
private $requestHeader;
|
||||
private $requestBody;
|
||||
private $responseHeader;
|
||||
private $responseBody;
|
||||
|
||||
public function __construct($message, $client, $code = 0, Exception $previous = null) {
|
||||
parent::__construct($message, $code, $previous);
|
||||
|
||||
$this->requestHeader = $client->GetHttpRequest();
|
||||
$this->requestBody = $client->GetBody();
|
||||
$this->responseHeader = $client->GetResponseHeaders();
|
||||
$this->responseBody = $client->GetResponseBody();
|
||||
}
|
||||
|
||||
public function __toString() {
|
||||
$string = '';
|
||||
$dom = new DOMDocument();
|
||||
$dom->preserveWhiteSpace = FALSE;
|
||||
$dom->formatOutput = TRUE;
|
||||
|
||||
$string .= '<pre>';
|
||||
$string .= 'Exception: '.$this->getMessage().'<br><br><br><br>';
|
||||
$string .= 'If you think there is a bug in SimpleCalDAV, please report the following information on github or send it at palm.michael@gmx.de.<br><br><br>';
|
||||
$string .= '<br>For debugging purposes:<br>';
|
||||
$string .= '<br>last request:<br><br>';
|
||||
|
||||
$string .= $this->requestHeader;
|
||||
|
||||
if(!empty($this->requestBody)) {
|
||||
|
||||
if(!preg_match( '#^Content-type:.*?text/calendar.*?$#', $this->requestHeader, $matches)) {
|
||||
$dom->loadXML($this->requestBody);
|
||||
$string .= htmlentities($dom->saveXml());
|
||||
}
|
||||
|
||||
else $string .= htmlentities($this->requestBody).'<br><br>';
|
||||
}
|
||||
|
||||
$string .= '<br>last response:<br><br>';
|
||||
|
||||
$string .= $this->responseHeader;
|
||||
|
||||
if(!empty($this->responseBody)) {
|
||||
if(!preg_match( '#^Content-type:.*?text/calendar.*?$#', $this->responseHeader, $matches)) {
|
||||
$dom->loadXML($this->responseBody);
|
||||
$string .= htmlentities($dom->saveXml());
|
||||
}
|
||||
|
||||
else $string .= htmlentities($this->responseBody);
|
||||
}
|
||||
|
||||
$string .= '<br><br>';
|
||||
|
||||
$string .= 'Trace:<br><br>'.$this->getTraceAsString();
|
||||
|
||||
$string .= '</pre>';
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
public function getRequestHeader() {
|
||||
return $this->requestHeader;
|
||||
}
|
||||
|
||||
public function getrequestBody() {
|
||||
return $this->requestBody;
|
||||
}
|
||||
|
||||
public function getResponseHeader() {
|
||||
return $this->responseHeader;
|
||||
}
|
||||
|
||||
public function getresponseBody() {
|
||||
return $this->responseBody;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,151 @@
|
|||
<?php
|
||||
/**
|
||||
* CalDAVFilter
|
||||
*
|
||||
* Copyright 2014 Michael Palm <palm.michael@gmx.de>
|
||||
*
|
||||
* This class represents a filter, which can be used to get a custom report of
|
||||
* calendar resources (events, todos, etc.) from the CalDAV-Server
|
||||
*
|
||||
* resourceType: The type of resource you want to get. Has to be either
|
||||
* "VEVENT", "VTODO", "VJOURNAL", "VFREEBUSY" or "VALARM".
|
||||
* You have to decide.
|
||||
*
|
||||
* mustInclude(),
|
||||
* mustIncludeMatchSubstr(),
|
||||
* mustOverlapWithTimerange(): Use these functions for further filter-options
|
||||
*
|
||||
* toXML(): Transforms the filter to xml-code for the server. Used to pass as
|
||||
* argument for SimpleCalDAVClient->getCustomReport()
|
||||
*
|
||||
* @package simpleCalDAV
|
||||
*
|
||||
*/
|
||||
|
||||
class CalDAVFilter {
|
||||
private $resourceType;
|
||||
private $mustIncludes = array();
|
||||
|
||||
/*
|
||||
* @param $type The type of resource you want to get. Has to be either
|
||||
* "VEVENT", "VTODO", "VJOURNAL", "VFREEBUSY" or "VALARM".
|
||||
* You have to decide.
|
||||
*/
|
||||
public function __construct ( $type ) {
|
||||
$this->resourceType = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* function mustInclude()
|
||||
* Specifies that a certin property has to be included. The content of the
|
||||
* property is irrelevant.
|
||||
*
|
||||
* Only call this function and mustIncludeMatchSubstr() once per property!
|
||||
*
|
||||
* Examples:
|
||||
* mustInclude("SUMMARY"); specifies that all returned resources have to
|
||||
* have the SUMMARY-property.
|
||||
* mustInclude("LOCATION "); specifies that all returned resources have to
|
||||
* have the LOCATION-property.
|
||||
*
|
||||
* Arguments:
|
||||
* @param $field The name of the property. For a full list of valid
|
||||
* property names see http://www.rfcreader.com/#rfc5545_line3622
|
||||
* Note that the server might not support all of them.
|
||||
* @param $inverse Makes the effect inverse: The resource must NOT include
|
||||
* the property $field
|
||||
*/
|
||||
public function mustInclude ( $field, $inverse = FALSE ) {
|
||||
$this->mustIncludes[] = array("mustInclude", $field, $inverse);
|
||||
}
|
||||
|
||||
/**
|
||||
* function mustIncludeMatchSubstr()
|
||||
* Specifies that a certin property has to be included and that its value
|
||||
* has to match a given substring.
|
||||
*
|
||||
* Only call this function and mustInclude() once per property!
|
||||
*
|
||||
* Examples:
|
||||
* mustIncludeMatchSubstr("SUMMARY", "a part of the summary"); would return
|
||||
* a resource with "SUMMARY:This is a part of the summary" included, but no
|
||||
* resource with "SUMMARY:This is a part of the".
|
||||
*
|
||||
* Arguments:
|
||||
* @param $field The name of the property. For a full list of valid
|
||||
* property names see http://www.rfcreader.com/#rfc5545_line3622
|
||||
* Note that the server might not support all of them.
|
||||
* @param $substring Substring to match against the value of the property.
|
||||
* @param $inverse Makes the effect inverse: The property value must NOT
|
||||
* include the $substring
|
||||
*/
|
||||
public function mustIncludeMatchSubstr ( $field, $substring, $inverse = FALSE ) {
|
||||
$this->mustIncludes[] = array("mustIncludeMatchSubstr", $field, $substring, $inverse);
|
||||
}
|
||||
|
||||
/**
|
||||
* function mustOverlapWithTimerange()
|
||||
* Specifies that the resource has to overlap with a given timerange.
|
||||
* @see http://www.rfcreader.com/#rfc4791_line3944
|
||||
*
|
||||
* Only call this function once per CalDAVFilter-object!
|
||||
*
|
||||
* Arguments:
|
||||
* @param $start The starting point of the time interval. Must be in the format yyyymmddThhmmssZ and should be in
|
||||
* GMT. If omitted the value is set to -infinity.
|
||||
* @param $end The end point of the time interval. Must be in the format yyyymmddThhmmssZ and should be in
|
||||
* GMT. If omitted the value is set to +infinity.
|
||||
*/
|
||||
public function mustOverlapWithTimerange ( $start = NULL, $end = NULL) {
|
||||
// Are $start and $end in the correct format?
|
||||
if ( ( isset($start) and ! preg_match( '#^\d\d\d\d\d\d\d\dT\d\d\d\d\d\dZ$#', $start, $matches ) )
|
||||
or ( isset($end) and ! preg_match( '#^\d\d\d\d\d\d\d\dT\d\d\d\d\d\dZ$#', $end, $matches ) ) )
|
||||
{ trigger_error('$start or $end are in the wrong format. They must have the format yyyymmddThhmmssZ and should be in GMT', E_USER_ERROR); }
|
||||
|
||||
$this->mustIncludes[] = array("mustOverlapWithTimerange", $start, $end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the filter to xml-code for the server. Used to pass as
|
||||
* argument for SimpleCalDAVClient->getCustomReport()
|
||||
*
|
||||
* Example:
|
||||
* $simpleCalDAVClient->getCustomReport($filter->toXML());
|
||||
*
|
||||
* @see SimpleCalDAVClient.php
|
||||
*/
|
||||
public function toXML () {
|
||||
$xml = '<C:comp-filter name="VCALENDAR"><C:comp-filter name="'.$this->resourceType.'">';
|
||||
|
||||
foreach($this->mustIncludes as $filter) {
|
||||
switch($filter[0]) {
|
||||
case "mustInclude":
|
||||
$xml .= '<C:prop-filter name="'.$filter[1].'"';
|
||||
if(!$filter[2]) $xml .= '/>';
|
||||
else $xml .= '><C:is-not-defined/></C:prop-filter>';
|
||||
break;
|
||||
|
||||
case "mustIncludeMatchSubstr":
|
||||
$xml .= '<C:prop-filter name="'.$filter[1].'"><C:text-match';
|
||||
if($filter[3]) $xml .= ' negate-condition="yes"';
|
||||
$xml .= '>'.$filter[2].'</C:text-match></C:prop-filter>';
|
||||
break;
|
||||
|
||||
case "mustOverlapWithTimerange":
|
||||
if($this->resourceType == "VTODO") $xml .= '<C:comp-filter name="VALARM">';
|
||||
$xml .= '<C:time-range';
|
||||
if($filter[1] != NULL) $xml .= ' start="'.$filter[1].'"';
|
||||
if($filter[2] != NULL) $xml .= ' end="'.$filter[2].'"';
|
||||
$xml .= '/>';
|
||||
if($this->resourceType == "VTODO") $xml .= '</C:comp-filter>';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$xml .= '</C:comp-filter></C:comp-filter>';
|
||||
|
||||
return $xml;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
/**
|
||||
* CalDAVObject
|
||||
*
|
||||
* Copyright 2014 Michael Palm <palm.michael@gmx.de>
|
||||
*
|
||||
* This class represents a calendar resource on the CalDAV-Server (event, todo, etc.)
|
||||
*
|
||||
* href: The link to the resource in the calendar
|
||||
* data: The iCalendar-Data. The "heart" of the resource.
|
||||
* etag: The entity tag is a unique identifier, not only of a resource
|
||||
* like the unique ID, but of serveral versions of the same resource. This means that a resource with one unique
|
||||
* ID can have many different entity tags, depending on the content of the resource. One version of a resource,
|
||||
* i. e. one special description in combination with one special starting time, created at one specific time,
|
||||
* etc., has exactly on unique entity tag.
|
||||
* The assignment of an entity tag ensures, that you know what you are changing/deleting. It ensures, that no one
|
||||
* changed the resource between your viewing of the resource and your change/delete-request. Assigning an entity tag
|
||||
* provides you of accidently destroying the work of others.
|
||||
*
|
||||
* @package simpleCalDAV
|
||||
*
|
||||
*/
|
||||
|
||||
class CalDAVObject {
|
||||
private $href;
|
||||
private $data;
|
||||
private $etag;
|
||||
|
||||
public function __construct ($href, $data, $etag) {
|
||||
$this->href = $href;
|
||||
$this->data = $data;
|
||||
$this->etag = $etag;
|
||||
}
|
||||
|
||||
|
||||
// Getter
|
||||
|
||||
public function getHref () {
|
||||
return $this->href;
|
||||
}
|
||||
|
||||
public function getData () {
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
public function getEtag () {
|
||||
return $this->etag;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,3 +1,3 @@
|
|||
# gestion_ateliers
|
||||
|
||||
programmes permettant de simplifier et automatiser la gestion des ateliers dans dolibarr et les calendrier nextcloud
|
||||
programmes permettant de simplifier et automatiser la gestion des ateliers dans dolibarr et les calendriers nextcloud
|
||||
|
|
|
@ -0,0 +1,415 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* SimpleCalDAVClient
|
||||
*
|
||||
* Copyright 2014 Michael Palm <palm.michael@gmx.de>
|
||||
*
|
||||
* simpleCalDAV is a php library that allows you to connect to a calDAV-server to get event-, todo-
|
||||
* and free/busy-calendar resources from the server, to change them, to delete them, to create new ones, etc.
|
||||
* simpleCalDAV was made and tested for connections to the CalDAV-server Baikal 0.2.7. But it should work
|
||||
* with any other CalDAV-server too.
|
||||
*
|
||||
* It contains the following functions:
|
||||
* - connect()
|
||||
* - findCalendars()
|
||||
* - setCalendar()
|
||||
* - create()
|
||||
* - change()
|
||||
* - delete()
|
||||
* - getEvents()
|
||||
* - getTODOs()
|
||||
* - getCustomReport()
|
||||
*
|
||||
* All of those functions - except the last one - are realy easy to use, self-explanatory and are
|
||||
* deliverd with a big innitial comment, which explains all needed arguments and the return values.
|
||||
*
|
||||
* This library is heavily based on AgenDAV caldav-client-v2.php by Jorge López Pérez <jorge@adobo.org> which
|
||||
* again is heavily based on DAViCal caldav-client-v2.php by Andrew McMillan <andrew@mcmillan.net.nz>.
|
||||
* Actually, I hardly added any features. The main point of my work is to make everything straight
|
||||
* forward and easy to use. You can use simpleCalDAV whithout a deeper understanding of the
|
||||
* calDAV-protocol.
|
||||
*
|
||||
* Requirements of this library are
|
||||
* - The php extension cURL ( http://www.php.net/manual/en/book.curl.php )
|
||||
* - From Andrew’s Web Libraries: ( https://github.com/andrews-web-libraries/awl )
|
||||
* - XMLDocument.php
|
||||
* - XMLElement.php
|
||||
* - AWLUtilities.php
|
||||
*
|
||||
* @package simpleCalDAV
|
||||
*/
|
||||
|
||||
|
||||
|
||||
require_once('CalDAVClient.php');
|
||||
require_once('CalDAVException.php');
|
||||
require_once('CalDAVFilter.php');
|
||||
require_once('CalDAVObject.php');
|
||||
|
||||
class SimpleCalDAVClient {
|
||||
private $client;
|
||||
private $url;
|
||||
|
||||
/**
|
||||
* function connect()
|
||||
* Connects to a CalDAV-Server.
|
||||
*
|
||||
* Arguments:
|
||||
* @param $url URL to the CalDAV-server. E.g. http://exam.pl/baikal/cal.php/username/calendername/
|
||||
* @param $user Username to login with
|
||||
* @param $pass Password to login with
|
||||
*
|
||||
* Debugging:
|
||||
* @throws CalDAVException
|
||||
* For debugging purposes, just sorround everything with try { ... } catch (Exception $e) { echo $e->__toString(); }
|
||||
*/
|
||||
function connect ( $url, $user, $pass )
|
||||
{
|
||||
|
||||
// Connect to CalDAV-Server and log in
|
||||
$client = new CalDAVClient($url, $user, $pass);
|
||||
|
||||
// Valid CalDAV-Server? Or is it just a WebDAV-Server?
|
||||
if( ! $client->isValidCalDAVServer() )
|
||||
{
|
||||
|
||||
if( $client->GetHttpResultCode() == '401' ) // unauthorisized
|
||||
{
|
||||
throw new CalDAVException('Login failed', $client);
|
||||
}
|
||||
|
||||
elseif( $client->GetHttpResultCode() == '' ) // can't reach server
|
||||
{
|
||||
throw new CalDAVException('Can\'t reach server', $client);
|
||||
}
|
||||
|
||||
else throw new CalDAVException('Could\'n find a CalDAV-collection under the url', $client);
|
||||
}
|
||||
|
||||
// Check for errors
|
||||
if( $client->GetHttpResultCode() != '200' ) {
|
||||
if( $client->GetHttpResultCode() == '401' ) // unauthorisized
|
||||
{
|
||||
throw new CalDAVException('Login failed', $client);
|
||||
}
|
||||
|
||||
elseif( $client->GetHttpResultCode() == '' ) // can't reach server
|
||||
{
|
||||
throw new CalDAVException('Can\'t reach server', $client);
|
||||
}
|
||||
|
||||
else // Unknown status
|
||||
{
|
||||
throw new CalDAVException('Recieved unknown HTTP status while checking the connection after establishing it', $client);
|
||||
}
|
||||
}
|
||||
|
||||
$this->client = $client;
|
||||
}
|
||||
|
||||
/**
|
||||
* function findCalendars()
|
||||
*
|
||||
* Requests a list of all accessible calendars on the server
|
||||
*
|
||||
* Return value:
|
||||
* @return an array of CalDAVCalendar-Objects (see CalDAVCalendar.php), representing all calendars accessible by the current principal (user).
|
||||
*
|
||||
* Debugging:
|
||||
* @throws CalDAVException
|
||||
* For debugging purposes, just sorround everything with try { ... } catch (Exception $e) { echo $e->__toString(); exit(-1); }
|
||||
*/
|
||||
function findCalendars()
|
||||
{
|
||||
if(!isset($this->client)) throw new Exception('No connection. Try connect().');
|
||||
|
||||
return $this->client->FindCalendars(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* function setCalendar()
|
||||
*
|
||||
* Sets the actual calendar to work with
|
||||
*
|
||||
* Debugging:
|
||||
* @throws CalDAVException
|
||||
* For debugging purposes, just sorround everything with try { ... } catch (Exception $e) { echo $e->__toString(); exit(-1); }
|
||||
*/
|
||||
function setCalendar ( CalDAVCalendar $calendar )
|
||||
{
|
||||
if(!isset($this->client)) throw new Exception('No connection. Try connect().');
|
||||
|
||||
$this->client->SetCalendar($this->client->first_url_part.$calendar->getURL());
|
||||
|
||||
// Is there a '/' at the end of the calendar_url?
|
||||
if ( ! preg_match( '#^.*?/$#', $this->client->calendar_url, $matches ) ) { $this->url = $this->client->calendar_url.'/'; }
|
||||
else { $this->url = $this->client->calendar_url; }
|
||||
}
|
||||
|
||||
/**
|
||||
* function create()
|
||||
* Creates a new calendar resource on the CalDAV-Server (event, todo, etc.).
|
||||
*
|
||||
* Arguments:
|
||||
* @param $cal iCalendar-data of the resource you want to create.
|
||||
* Notice: The iCalendar-data contains the unique ID which specifies where the event is being saved.
|
||||
*
|
||||
* Return value:
|
||||
* @return An CalDAVObject-representation (see CalDAVObject.php) of your created resource
|
||||
*
|
||||
* Debugging:
|
||||
* @throws CalDAVException
|
||||
* For debugging purposes, just sorround everything with try { ... } catch (Exception $e) { echo $e->__toString(); exit(-1); }
|
||||
*/
|
||||
function create ( $cal )
|
||||
{
|
||||
// Connection and calendar set?
|
||||
if(!isset($this->client)) throw new Exception('No connection. Try connect().');
|
||||
if(!isset($this->client->calendar_url)) throw new Exception('No calendar selected. Try findCalendars() and setCalendar().');
|
||||
|
||||
// Parse $cal for UID
|
||||
if (! preg_match( '#^UID:(.*?)\r?\n?$#m', $cal, $matches ) ) { throw new Exception('Can\'t find UID in $cal'); }
|
||||
else { $uid = $matches[1]; }
|
||||
|
||||
// Does $this->url.$uid.'.ics' already exist?
|
||||
$result = $this->client->GetEntryByHref( $this->url.$uid.'.ics' );
|
||||
if ( $this->client->GetHttpResultCode() == '200' ) { throw new CalDAVException($this->url.$uid.'.ics already exists. UID not unique?', $this->client); }
|
||||
else if ( $this->client->GetHttpResultCode() == '404' );
|
||||
else throw new CalDAVException('Recieved unknown HTTP status', $this->client);
|
||||
|
||||
// Put it!
|
||||
$newEtag = $this->client->DoPUTRequest( $this->url.$uid.'.ics', $cal );
|
||||
|
||||
// PUT-request successfull?
|
||||
if ( $this->client->GetHttpResultCode() != '201' )
|
||||
{
|
||||
if ( $this->client->GetHttpResultCode() == '204' ) // $url.$uid.'.ics' already existed on server
|
||||
{
|
||||
throw new CalDAVException( $this->url.$uid.'.ics already existed. Entry has been overwritten.', $this->client);
|
||||
}
|
||||
|
||||
else // Unknown status
|
||||
{
|
||||
throw new CalDAVException('Recieved unknown HTTP status', $this->client);
|
||||
}
|
||||
}
|
||||
|
||||
return new CalDAVObject($this->url.$uid.'.ics', $cal, $newEtag);
|
||||
}
|
||||
|
||||
/**
|
||||
* function change()
|
||||
* Changes a calendar resource (event, todo, etc.) on the CalDAV-Server.
|
||||
*
|
||||
* Arguments:
|
||||
* @param $href See CalDAVObject.php
|
||||
* @param $cal The new iCalendar-data that should be used to overwrite the old one.
|
||||
* @param $etag See CalDAVObject.php
|
||||
*
|
||||
* Return value:
|
||||
* @return An CalDAVObject-representation (see CalDAVObject.php) of your changed resource
|
||||
*
|
||||
* Debugging:
|
||||
* @throws CalDAVException
|
||||
* For debugging purposes, just sorround everything with try { ... } catch (Exception $e) { echo $e->__toString(); exit(-1); }
|
||||
*/
|
||||
function change ( $href, $new_data, $etag )
|
||||
{
|
||||
// Connection and calendar set?
|
||||
if(!isset($this->client)) throw new Exception('No connection. Try connect().');
|
||||
if(!isset($this->client->calendar_url)) throw new Exception('No calendar selected. Try findCalendars() and setCalendar().');
|
||||
|
||||
// Does $href exist?
|
||||
$result = $this->client->GetEntryByHref($href);
|
||||
if ( $this->client->GetHttpResultCode() == '200' );
|
||||
else if ( $this->client->GetHttpResultCode() == '404' ) throw new CalDAVException('Can\'t find '.$href.' on the server', $this->client);
|
||||
else throw new CalDAVException('Recieved unknown HTTP status', $this->client);
|
||||
|
||||
// $etag correct?
|
||||
if($result[0]['etag'] != $etag) { throw new CalDAVException('Wrong entity tag. The entity seems to have changed.', $this->client); }
|
||||
|
||||
// Put it!
|
||||
$newEtag = $this->client->DoPUTRequest( $href, $new_data, $etag );
|
||||
|
||||
// PUT-request successfull?
|
||||
if ( $this->client->GetHttpResultCode() != '204' && $this->client->GetHttpResultCode() != '200' )
|
||||
{
|
||||
throw new CalDAVException('Recieved unknown HTTP status', $this->client);
|
||||
}
|
||||
|
||||
return new CalDAVObject($href, $new_data, $newEtag);
|
||||
}
|
||||
|
||||
/**
|
||||
* function delete()
|
||||
* Delets an event or a TODO from the CalDAV-Server.
|
||||
*
|
||||
* Arguments:
|
||||
* @param $href See CalDAVObject.php
|
||||
* @param $etag See CalDAVObject.php
|
||||
*
|
||||
* Debugging:
|
||||
* @throws CalDAVException
|
||||
* For debugging purposes, just sorround everything with try { ... } catch (Exception $e) { echo $e->__toString(); exit(-1); }
|
||||
*/
|
||||
function delete ( $href, $etag )
|
||||
{
|
||||
// Connection and calendar set?
|
||||
if(!isset($this->client)) throw new Exception('No connection. Try connect().');
|
||||
if(!isset($this->client->calendar_url)) throw new Exception('No calendar selected. Try findCalendars() and setCalendar().');
|
||||
|
||||
// Does $href exist?
|
||||
$result = $this->client->GetEntryByHref($href);
|
||||
if(count($result) == 0) throw new CalDAVException('Can\'t find '.$href.'on server', $this->client);
|
||||
|
||||
// $etag correct?
|
||||
if($result[0]['etag'] != $etag) { throw new CalDAVException('Wrong entity tag. The entity seems to have changed.', $this->client); }
|
||||
|
||||
// Do the deletion
|
||||
$this->client->DoDELETERequest($href, $etag);
|
||||
|
||||
// Deletion successfull?
|
||||
if ( $this->client->GetHttpResultCode() != '200' and $this->client->GetHttpResultCode() != '204' )
|
||||
{
|
||||
throw new CalDAVException('Recieved unknown HTTP status', $this->client);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* function getEvents()
|
||||
* Gets a all events from the CalDAV-Server which lie in a defined time interval.
|
||||
*
|
||||
* Arguments:
|
||||
* @param $start The starting point of the time interval. Must be in the format yyyymmddThhmmssZ and should be in
|
||||
* GMT. If omitted the value is set to -infinity.
|
||||
* @param $end The end point of the time interval. Must be in the format yyyymmddThhmmssZ and should be in
|
||||
* GMT. If omitted the value is set to +infinity.
|
||||
*
|
||||
* Return value:
|
||||
* @return an array of CalDAVObjects (See CalDAVObject.php), representing the found events.
|
||||
*
|
||||
* Debugging:
|
||||
* @throws CalDAVException
|
||||
* For debugging purposes, just sorround everything with try { ... } catch (Exception $e) { echo $e->__toString(); exit(-1); }
|
||||
*/
|
||||
function getEvents ( $start = null, $end = null )
|
||||
{
|
||||
// Connection and calendar set?
|
||||
if(!isset($this->client)) throw new Exception('No connection. Try connect().');
|
||||
if(!isset($this->client->calendar_url)) throw new Exception('No calendar selected. Try findCalendars() and setCalendar().');
|
||||
|
||||
// Are $start and $end in the correct format?
|
||||
if ( ( isset($start) and ! preg_match( '#^\d\d\d\d\d\d\d\dT\d\d\d\d\d\dZ$#', $start, $matches ) )
|
||||
or ( isset($end) and ! preg_match( '#^\d\d\d\d\d\d\d\dT\d\d\d\d\d\dZ$#', $end, $matches ) ) )
|
||||
{ trigger_error('$start or $end are in the wrong format. They must have the format yyyymmddThhmmssZ and should be in GMT', E_USER_ERROR); }
|
||||
|
||||
// Get it!
|
||||
$results = $this->client->GetEvents( $start, $end );
|
||||
|
||||
// GET-request successfull?
|
||||
if ( $this->client->GetHttpResultCode() != '207' )
|
||||
{
|
||||
throw new CalDAVException('Recieved unknown HTTP status', $this->client);
|
||||
}
|
||||
|
||||
// Reformat
|
||||
$report = array();
|
||||
foreach($results as $event) $report[] = new CalDAVObject($this->url.$event['href'], $event['data'], $event['etag']);
|
||||
|
||||
return $report;
|
||||
}
|
||||
|
||||
/**
|
||||
* function getTODOs()
|
||||
* Gets a all TODOs from the CalDAV-Server which lie in a defined time interval and match the
|
||||
* given criteria.
|
||||
*
|
||||
* Arguments:
|
||||
* @param $start The starting point of the time interval. Must be in the format yyyymmddThhmmssZ and should be in
|
||||
* GMT. If omitted the value is set to -infinity.
|
||||
* @param $end The end point of the time interval. Must be in the format yyyymmddThhmmssZ and should be in
|
||||
* GMT. If omitted the value is set to +infinity.
|
||||
* @param $complete Filter for completed tasks (true) or for uncompleted tasks (false). If omitted, the function will return both.
|
||||
* @param $cancelled Filter for cancelled tasks (true) or for uncancelled tasks (false). If omitted, the function will return both.
|
||||
*
|
||||
* Return value:
|
||||
* @return an array of CalDAVObjects (See CalDAVObject.php), representing the found TODOs.
|
||||
*
|
||||
* Debugging:
|
||||
* @throws CalDAVException
|
||||
* For debugging purposes, just sorround everything with try { ... } catch (Exception $e) { echo $e->__toString(); exit(-1); }
|
||||
*/
|
||||
function getTODOs ( $start = null, $end = null, $completed = null, $cancelled = null )
|
||||
{
|
||||
// Connection and calendar set?
|
||||
if(!isset($this->client)) throw new Exception('No connection. Try connect().');
|
||||
if(!isset($this->client->calendar_url)) throw new Exception('No calendar selected. Try findCalendars() and setCalendar().');
|
||||
|
||||
// Are $start and $end in the correct format?
|
||||
if ( ( isset($start) and ! preg_match( '#^\d\d\d\d\d\d\d\dT\d\d\d\d\d\dZ$#', $start, $matches ) )
|
||||
or ( isset($end) and ! preg_match( '#^\d\d\d\d\d\d\d\dT\d\d\d\d\d\dZ$#', $end, $matches ) ) )
|
||||
{ trigger_error('$start or $end are in the wrong format. They must have the format yyyymmddThhmmssZ and should be in GMT', E_USER_ERROR); }
|
||||
|
||||
// Get it!
|
||||
$results = $this->client->GetTodos( $start, $end, $completed, $cancelled );
|
||||
|
||||
// GET-request successfull?
|
||||
if ( $this->client->GetHttpResultCode() != '207' )
|
||||
{
|
||||
throw new CalDAVException('Recieved unknown HTTP status', $this->client);
|
||||
}
|
||||
|
||||
// Reformat
|
||||
$report = array();
|
||||
foreach($results as $event) $report[] = new CalDAVObject($this->url.$event['href'], $event['data'], $event['etag']);
|
||||
|
||||
return $report;
|
||||
}
|
||||
|
||||
/**
|
||||
* function getCustomReport()
|
||||
* Sends a custom request to the server
|
||||
* (Sends a REPORT-request with a custom <C:filter>-tag)
|
||||
*
|
||||
* You can either write the filterXML yourself or build an CalDAVFilter-object (see CalDAVFilter.php).
|
||||
*
|
||||
* See http://www.rfcreader.com/#rfc4791_line1524 for more information about how to write filters on your own.
|
||||
*
|
||||
* Arguments:
|
||||
* @param $filterXML The stuff, you want to send encapsulated in the <C:filter>-tag.
|
||||
*
|
||||
* Return value:
|
||||
* @return an array of CalDAVObjects (See CalDAVObject.php), representing the found calendar resources.
|
||||
*
|
||||
* Debugging:
|
||||
* @throws CalDAVException
|
||||
* For debugging purposes, just sorround everything with try { ... } catch (Exception $e) { echo $e->__toString(); exit(-1); }
|
||||
*/
|
||||
function getCustomReport ( $filterXML )
|
||||
{
|
||||
// Connection and calendar set?
|
||||
if(!isset($this->client)) throw new Exception('No connection. Try connect().');
|
||||
if(!isset($this->client->calendar_url)) throw new Exception('No calendar selected. Try findCalendars() and setCalendar().');
|
||||
|
||||
// Get report!
|
||||
$this->client->SetDepth('1');
|
||||
|
||||
// Get it!
|
||||
$results = $this->client->DoCalendarQuery('<C:filter>'.$filterXML.'</C:filter>');
|
||||
|
||||
// GET-request successfull?
|
||||
if ( $this->client->GetHttpResultCode() != '207' )
|
||||
{
|
||||
throw new CalDAVException('Recieved unknown HTTP status', $this->client);
|
||||
}
|
||||
|
||||
// Reformat
|
||||
$report = array();
|
||||
foreach($results as $event) $report[] = new CalDAVObject($this->url.$event['href'], $event['data'], $event['etag']);
|
||||
|
||||
return $report;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
/**
|
||||
* listCalendars
|
||||
*
|
||||
* Copyright 2014 Michael Palm <palm.michael@gmx.de>
|
||||
*
|
||||
* Open this file in a webbrowser to view a list of all accessible calendars
|
||||
* on the server and the information related to those calendars. It can be used
|
||||
* to determine the calendar-id, needed for SimpleCalDAV.
|
||||
*
|
||||
* @package simpleCalDAV
|
||||
*/
|
||||
|
||||
require_once('../SimpleCalDAVClient.php');
|
||||
|
||||
if($_POST == null) {
|
||||
echo '
|
||||
<form action="#" method="post">
|
||||
<p>This formular can be used to view a list of all accessible calendars on the server and the information related to those calendars. It can be used to determine the calendar-id, needed for SimpleCalDAV.</p>
|
||||
<p>Calendar-URL:<br><input name="url" type="text" size="30" maxlength="100"></p>
|
||||
<p>Username:<br><input name="user" type="text" size="30" maxlength="100"></p>
|
||||
<p>Password:<br><input name="pass" type="text" size="30" maxlength="100"></p>
|
||||
<input type="submit" value=" Show! ">
|
||||
</form>';
|
||||
}
|
||||
|
||||
else {
|
||||
$client = new SimpleCalDAVClient();
|
||||
|
||||
try {
|
||||
$client->connect($_POST['url'], $_POST['user'], $_POST['pass']);
|
||||
|
||||
$calendars = $client->findCalendars();
|
||||
|
||||
echo'
|
||||
<table>';
|
||||
|
||||
$i = 0;
|
||||
foreach($calendars as $cal) {
|
||||
$i++;
|
||||
|
||||
echo '
|
||||
<tr> <td></td> <td><strong>Calendar #'.$i.'</strong></td> </tr>
|
||||
<tr> <td>URL:</td> <td>'.$cal->getURL().'</td> </tr>
|
||||
<tr> <td>Display Name:</td> <td>'.$cal->getDisplayName().'</td> </tr>
|
||||
<tr> <td>Calendar ID:</td> <td>'.$cal->getCalendarID().'</td> </tr>
|
||||
<tr> <td>CTAG:</td> <td>'.$cal->getCTag().'</td> </tr>
|
||||
<tr> <td>RBG-Color:</td> <td>'.$cal->getRBGcolor().'</td> </tr>
|
||||
<tr> <td>Order:</td> <td>'.$cal->getOrder().'</td> </tr>
|
||||
<tr> <td></td> <td></td> </tr>';
|
||||
}
|
||||
|
||||
echo '
|
||||
</table>';
|
||||
}
|
||||
|
||||
catch (Exception $e) {
|
||||
echo $e->__toString();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,691 @@
|
|||
<?php
|
||||
/**
|
||||
* Utility functions of a general nature which are used by
|
||||
* most AWL library classes.
|
||||
*
|
||||
* @package awl
|
||||
* @subpackage Utilities
|
||||
* @author Andrew McMillan <andrew@mcmillan.net.nz>
|
||||
* @copyright Catalyst IT Ltd, Morphoss Ltd <http://www.morphoss.com/>
|
||||
* @license http://www.gnu.org/licenses/lgpl-3.0.txt GNU LGPL version 3 or later
|
||||
*/
|
||||
|
||||
if ( !function_exists('dbg_error_log') ) {
|
||||
/**
|
||||
* Writes a debug message into the error log using printf syntax. If the first
|
||||
* parameter is "ERROR" then the message will _always_ be logged.
|
||||
* Otherwise, the first parameter is a "component" name, and will only be logged
|
||||
* if $c->dbg["component"] is set to some non-null value.
|
||||
*
|
||||
* If you want to see every log message then $c->dbg["ALL"] can be set, to
|
||||
* override the debugging status of the individual components.
|
||||
*
|
||||
* @var string $component The component to identify itself, or "ERROR", or "LOG:component"
|
||||
* @var string $format A format string for the log message
|
||||
* @var [string $parameter ...] Parameters for the format string.
|
||||
*/
|
||||
function dbg_error_log() {
|
||||
global $c;
|
||||
$args = func_get_args();
|
||||
$type = "DBG";
|
||||
$component = array_shift($args);
|
||||
if ( substr( $component, 0, 3) == "LOG" ) {
|
||||
// Special escape case for stuff that always gets logged.
|
||||
$type = 'LOG';
|
||||
$component = substr($component,4);
|
||||
}
|
||||
else if ( $component == "ERROR" ) {
|
||||
$type = "***";
|
||||
}
|
||||
else if ( isset($c->dbg["ALL"]) ) {
|
||||
$type = "ALL";
|
||||
}
|
||||
else if ( !isset($c->dbg[strtolower($component)]) ) return;
|
||||
|
||||
$argc = func_num_args();
|
||||
if ( 2 <= $argc ) {
|
||||
$format = array_shift($args);
|
||||
}
|
||||
else {
|
||||
$format = "%s";
|
||||
}
|
||||
@error_log( $c->sysabbr.": $type: $component:". vsprintf( $format, $args ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( !function_exists('fatal') ) {
|
||||
function fatal() {
|
||||
global $c;
|
||||
$args = func_get_args();
|
||||
$argc = func_num_args();
|
||||
if ( 2 <= $argc ) {
|
||||
$format = array_shift($args);
|
||||
}
|
||||
else {
|
||||
$format = "%s";
|
||||
}
|
||||
@error_log( $c->sysabbr.": FATAL: $component:". vsprintf( $format, $args ) );
|
||||
|
||||
@error_log( "================= Stack Trace ===================" );
|
||||
|
||||
$trace = array_reverse(debug_backtrace());
|
||||
array_pop($trace);
|
||||
foreach( $trace AS $k => $v ) {
|
||||
@error_log( sprintf(" ===> %s[%d] calls %s%s%s()",
|
||||
$v['file'],
|
||||
$v['line'],
|
||||
(isset($v['class'])?$v['class']:''),
|
||||
(isset($v['type'])?$v['type']:''),
|
||||
(isset($v['function'])?$v['function']:'')
|
||||
));
|
||||
}
|
||||
echo "Fatal Error";
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( !function_exists('trace_bug') ) {
|
||||
/**
|
||||
* Not as sever as a fatal() call, but we want to log and trace it
|
||||
*/
|
||||
function trace_bug() {
|
||||
global $c;
|
||||
$args = func_get_args();
|
||||
$argc = func_num_args();
|
||||
if ( 2 <= $argc ) {
|
||||
$format = array_shift($args);
|
||||
}
|
||||
else {
|
||||
$format = "%s";
|
||||
}
|
||||
@error_log( $c->sysabbr.": BUG: $component:". vsprintf( $format, $args ) );
|
||||
|
||||
@error_log( "================= Stack Trace ===================" );
|
||||
|
||||
$trace = array_reverse(debug_backtrace());
|
||||
array_pop($trace);
|
||||
foreach( $trace AS $k => $v ) {
|
||||
@error_log( sprintf(" ===> %s[%d] calls %s%s%s()",
|
||||
$v['file'],
|
||||
$v['line'],
|
||||
(isset($v['class'])?$v['class']:''),
|
||||
(isset($v['type'])?$v['type']:''),
|
||||
(isset($v['function'])?$v['function']:'')
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( !function_exists('apache_request_headers') ) {
|
||||
/**
|
||||
* Compatibility so we can use the apache function name and still work with CGI
|
||||
* @package awl
|
||||
*/
|
||||
eval('
|
||||
function apache_request_headers() {
|
||||
foreach($_SERVER as $key=>$value) {
|
||||
if (substr($key,0,5)=="HTTP_") {
|
||||
$key=str_replace(" ","-",ucwords(strtolower(str_replace("_"," ",substr($key,5)))));
|
||||
$out[$key]=$value;
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
');
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ( !function_exists('dbg_log_array') ) {
|
||||
/**
|
||||
* Function to dump an array to the error log, possibly recursively
|
||||
*
|
||||
* @var string $component Which component should this log message identify itself from
|
||||
* @var string $name What name should this array dump identify itself as
|
||||
* @var array $arr The array to be dumped.
|
||||
* @var boolean $recursive Should the dump recurse into arrays/objects in the array
|
||||
*/
|
||||
function dbg_log_array( $component, $name, $arr, $recursive = false ) {
|
||||
if ( !isset($arr) || (gettype($arr) != 'array' && gettype($arr) != 'object') ) {
|
||||
dbg_error_log( $component, "%s: array is not set, or is not an array!", $name);
|
||||
return;
|
||||
}
|
||||
foreach ($arr as $key => $value) {
|
||||
dbg_error_log( $component, "%s: >>%s<< = >>%s<<", $name, $key,
|
||||
(gettype($value) == 'array' || gettype($value) == 'object' ? gettype($value) : $value) );
|
||||
if ( $recursive && (gettype($value) == 'array' || (gettype($value) == 'object' && "$key" != 'self' && "$key" != 'parent') ) ) {
|
||||
dbg_log_array( $component, "$name"."[$key]", $value, $recursive );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ( !function_exists("session_simple_md5") ) {
|
||||
/**
|
||||
* Make a plain MD5 hash of a string, identifying the type of hash it is
|
||||
*
|
||||
* @param string $instr The string to be salted and MD5'd
|
||||
* @return string The *MD5* and the MD5 of the string
|
||||
*/
|
||||
function session_simple_md5( $instr ) {
|
||||
global $c;
|
||||
if ( isset($c->dbg['password']) ) dbg_error_log( "Login", "Making plain MD5: instr=$instr, md5($instr)=".md5($instr) );
|
||||
return ( '*MD5*'. md5($instr) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ( !function_exists("session_salted_md5") ) {
|
||||
/**
|
||||
* Make a salted MD5 string, given a string and (possibly) a salt.
|
||||
*
|
||||
* If no salt is supplied we will generate a random one.
|
||||
*
|
||||
* @param string $instr The string to be salted and MD5'd
|
||||
* @param string $salt Some salt to sprinkle into the string to be MD5'd so we don't get the same PW always hashing to the same value.
|
||||
* @return string The salt, a * and the MD5 of the salted string, as in SALT*SALTEDHASH
|
||||
*/
|
||||
function session_salted_md5( $instr, $salt = "" ) {
|
||||
if ( $salt == "" ) $salt = substr( md5(rand(100000,999999)), 2, 8);
|
||||
global $c;
|
||||
if ( isset($c->dbg['password']) ) dbg_error_log( "Login", "Making salted MD5: salt=$salt, instr=$instr, md5($salt$instr)=".md5($salt . $instr) );
|
||||
return ( sprintf("*%s*%s", $salt, md5($salt . $instr) ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ( !function_exists("session_salted_sha1") ) {
|
||||
/**
|
||||
* Make a salted SHA1 string, given a string and (possibly) a salt. PHP5 only (although it
|
||||
* could be made to work on PHP4 (@see http://www.openldap.org/faq/data/cache/347.html). The
|
||||
* algorithm used here is compatible with OpenLDAP so passwords generated through this function
|
||||
* should be able to be migrated to OpenLDAP by using the part following the second '*', i.e.
|
||||
* the '{SSHA}....' part.
|
||||
*
|
||||
* If no salt is supplied we will generate a random one.
|
||||
*
|
||||
* @param string $instr The string to be salted and SHA1'd
|
||||
* @param string $salt Some salt to sprinkle into the string to be SHA1'd so we don't get the same PW always hashing to the same value.
|
||||
* @return string A *, the salt, a * and the SHA1 of the salted string, as in *SALT*SALTEDHASH
|
||||
*/
|
||||
function session_salted_sha1( $instr, $salt = "" ) {
|
||||
if ( $salt == "" ) $salt = substr( str_replace('*','',base64_encode(sha1(rand(100000,9999999),true))), 2, 9);
|
||||
global $c;
|
||||
if ( isset($c->dbg['password']) ) dbg_error_log( "Login", "Making salted SHA1: salt=$salt, instr=$instr, encoded($instr$salt)=".base64_encode(sha1($instr . $salt, true).$salt) );
|
||||
return ( sprintf("*%s*{SSHA}%s", $salt, base64_encode(sha1($instr.$salt, true) . $salt ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( !function_exists("session_validate_password") ) {
|
||||
|
||||
/**
|
||||
* Checks what a user entered against the actual password on their account.
|
||||
* @param string $they_sent What the user entered.
|
||||
* @param string $we_have What we have in the database as their password. Which may (or may not) be a salted MD5.
|
||||
* @return boolean Whether or not the users attempt matches what is already on file.
|
||||
*/
|
||||
function session_validate_password( $they_sent, $we_have ) {
|
||||
global $c;
|
||||
if ( preg_match('/^\*\*.+$/', $we_have ) ) {
|
||||
// The "forced" style of "**plaintext" to allow easier admin setting
|
||||
return ( "**$they_sent" == $we_have );
|
||||
}
|
||||
|
||||
if ( isset($c->wp_includes) && substring($we_have,0,1) == '$' ) {
|
||||
// Include Wordpress password handling, if it's in the path.
|
||||
@require_once($c->wp_includes .'/class-phpass.php');
|
||||
|
||||
if ( class_exists('PasswordHash') ) {
|
||||
$wp_hasher = new PasswordHash(8, true);
|
||||
return $wp_hasher->CheckPassword($password, $hash);
|
||||
}
|
||||
}
|
||||
|
||||
if ( preg_match('/^\*(.+)\*{[A-Z]+}.+$/', $we_have, $regs ) ) {
|
||||
if ( function_exists("session_salted_sha1") ) {
|
||||
// A nicely salted sha1sum like "*<salt>*{SSHA}<salted_sha1>"
|
||||
$salt = $regs[1];
|
||||
$sha1_sent = session_salted_sha1( $they_sent, $salt ) ;
|
||||
return ( $sha1_sent == $we_have );
|
||||
}
|
||||
else {
|
||||
dbg_error_log( "ERROR", "Password is salted SHA-1 but you are using PHP4!" );
|
||||
echo <<<EOERRMSG
|
||||
<html>
|
||||
<head>
|
||||
<title>Salted SHA1 Password format not supported with PHP4</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Salted SHA1 Password format not supported with PHP4</h1>
|
||||
<p>At some point you have used PHP5 to set the password for this user and now you are
|
||||
using PHP4. You will need to assign a new password to this user using PHP4, or ensure
|
||||
you use PHP5 everywhere (recommended).</p>
|
||||
<p>AWL has now switched to using salted SHA-1 passwords by preference in a format
|
||||
compatible with OpenLDAP.</p>
|
||||
</body>
|
||||
</html>
|
||||
EOERRMSG;
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
if ( preg_match('/^\*MD5\*.+$/', $we_have, $regs ) ) {
|
||||
// A crappy unsalted md5sum like "*MD5*<md5>"
|
||||
$md5_sent = session_simple_md5( $they_sent ) ;
|
||||
return ( $md5_sent == $we_have );
|
||||
}
|
||||
else if ( preg_match('/^\*(.+)\*.+$/', $we_have, $regs ) ) {
|
||||
// A nicely salted md5sum like "*<salt>*<salted_md5>"
|
||||
$salt = $regs[1];
|
||||
$md5_sent = session_salted_md5( $they_sent, $salt ) ;
|
||||
return ( $md5_sent == $we_have );
|
||||
}
|
||||
|
||||
// Anything else is bad
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ( !function_exists("replace_uri_params") ) {
|
||||
/**
|
||||
* Given a URL (presumably the current one) and a parameter, replace the value of parameter,
|
||||
* extending the URL as necessary if the parameter is not already there.
|
||||
* @param string $uri The URI we will be replacing parameters in.
|
||||
* @param array $replacements An array of replacement pairs array( "replace_this" => "with this" )
|
||||
* @return string The URI with the replacements done.
|
||||
*/
|
||||
function replace_uri_params( $uri, $replacements ) {
|
||||
$replaced = $uri;
|
||||
foreach( $replacements AS $param => $new_value ) {
|
||||
$rxp = preg_replace( '/([\[\]])/', '\\\\$1', $param ); // Some parameters may be arrays.
|
||||
$regex = "/([&?])($rxp)=([^&]+)/";
|
||||
dbg_error_log("core", "Looking for [%s] to replace with [%s] regex is %s and searching [%s]", $param, $new_value, $regex, $replaced );
|
||||
if ( preg_match( $regex, $replaced ) )
|
||||
$replaced = preg_replace( $regex, "\$1$param=$new_value", $replaced);
|
||||
else
|
||||
$replaced .= "&$param=$new_value";
|
||||
}
|
||||
if ( ! preg_match( '/\?/', $replaced ) ) {
|
||||
$replaced = preg_replace("/&(.+)$/", "?\$1", $replaced);
|
||||
}
|
||||
$replaced = str_replace("&", "--AmPeRsAnD--", $replaced);
|
||||
$replaced = str_replace("&", "&", $replaced);
|
||||
$replaced = str_replace("--AmPeRsAnD--", "&", $replaced);
|
||||
dbg_error_log("core", "URI <<$uri>> morphed to <<$replaced>>");
|
||||
return $replaced;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( !function_exists("uuid") ) {
|
||||
/**
|
||||
* Generates a Universally Unique IDentifier, version 4.
|
||||
*
|
||||
* RFC 4122 (http://www.ietf.org/rfc/rfc4122.txt) defines a special type of Globally
|
||||
* Unique IDentifiers (GUID), as well as several methods for producing them. One
|
||||
* such method, described in section 4.4, is based on truly random or pseudo-random
|
||||
* number generators, and is therefore implementable in a language like PHP.
|
||||
*
|
||||
* We choose to produce pseudo-random numbers with the Mersenne Twister, and to always
|
||||
* limit single generated numbers to 16 bits (ie. the decimal value 65535). That is
|
||||
* because, even on 32-bit systems, PHP's RAND_MAX will often be the maximum *signed*
|
||||
* value, with only the equivalent of 31 significant bits. Producing two 16-bit random
|
||||
* numbers to make up a 32-bit one is less efficient, but guarantees that all 32 bits
|
||||
* are random.
|
||||
*
|
||||
* The algorithm for version 4 UUIDs (ie. those based on random number generators)
|
||||
* states that all 128 bits separated into the various fields (32 bits, 16 bits, 16 bits,
|
||||
* 8 bits and 8 bits, 48 bits) should be random, except : (a) the version number should
|
||||
* be the last 4 bits in the 3rd field, and (b) bits 6 and 7 of the 4th field should
|
||||
* be 01. We try to conform to that definition as efficiently as possible, generating
|
||||
* smaller values where possible, and minimizing the number of base conversions.
|
||||
*
|
||||
* @copyright Copyright (c) CFD Labs, 2006. This function may be used freely for
|
||||
* any purpose ; it is distributed without any form of warranty whatsoever.
|
||||
* @author David Holmes <dholmes@cfdsoftware.net>
|
||||
*
|
||||
* @return string A UUID, made up of 32 hex digits and 4 hyphens.
|
||||
*/
|
||||
|
||||
function uuid() {
|
||||
|
||||
// The field names refer to RFC 4122 section 4.1.2
|
||||
|
||||
return sprintf('%04x%04x-%04x-%03x4-%04x-%04x%04x%04x',
|
||||
mt_rand(0, 65535), mt_rand(0, 65535), // 32 bits for "time_low"
|
||||
mt_rand(0, 65535), // 16 bits for "time_mid"
|
||||
mt_rand(0, 4095), // 12 bits before the 0100 of (version) 4 for "time_hi_and_version"
|
||||
bindec(substr_replace(sprintf('%016b', mt_rand(0, 65535)), '01', 6, 2)),
|
||||
// 8 bits, the last two of which (positions 6 and 7) are 01, for "clk_seq_hi_res"
|
||||
// (hence, the 2nd hex digit after the 3rd hyphen can only be 1, 5, 9 or d)
|
||||
// 8 bits for "clk_seq_low"
|
||||
mt_rand(0, 65535), mt_rand(0, 65535), mt_rand(0, 65535) // 48 bits for "node"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ( !function_exists("translate") ) {
|
||||
require("Translation.php");
|
||||
}
|
||||
|
||||
if ( !function_exists("clone") && version_compare(phpversion(), '5.0') < 0) {
|
||||
/**
|
||||
* PHP5 screws with the assignment operator changing so that $a = $b means that
|
||||
* $a becomes a reference to $b. There is a clone() that we can use in PHP5, so
|
||||
* we have to emulate that for PHP4. Bleargh.
|
||||
*/
|
||||
eval( 'function clone($object) { return $object; }' );
|
||||
}
|
||||
|
||||
if ( !function_exists("quoted_printable_encode") ) {
|
||||
/**
|
||||
* Process a string to fit the requirements of RFC2045 section 6.7. Note that
|
||||
* this works, but replaces more characters than the minimum set. For readability
|
||||
* the spaces aren't encoded as =20 though.
|
||||
*/
|
||||
function quoted_printable_encode($string) {
|
||||
return preg_replace('/[^\r\n]{73}[^=\r\n]{2}/', "$0=\r\n", str_replace("%","=",str_replace("%20"," ",rawurlencode($string))));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( !function_exists("check_by_regex") ) {
|
||||
/**
|
||||
* Verify a value is OK by testing a regex against it. If it is an array apply it to
|
||||
* each element in the array recursively. If it is an object we don't mess
|
||||
* with it.
|
||||
*/
|
||||
function check_by_regex( $val, $regex ) {
|
||||
if ( is_null($val) ) return null;
|
||||
switch( $regex ) {
|
||||
case 'int': $regex = '#^\d+$#'; break;
|
||||
}
|
||||
if ( is_array($val) ) {
|
||||
foreach( $val AS $k => $v ) {
|
||||
$val[$k] = check_by_regex($v,$regex);
|
||||
}
|
||||
}
|
||||
else if ( ! is_object($val) ) {
|
||||
if ( preg_match( $regex, $val, $matches) ) {
|
||||
$val = $matches[0];
|
||||
}
|
||||
else {
|
||||
$val = '';
|
||||
}
|
||||
}
|
||||
return $val;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( !function_exists("param_to_global") ) {
|
||||
/**
|
||||
* Convert a parameter to a global. We first look in _POST and then in _GET,
|
||||
* and if they passed in a bunch of valid characters, we will make sure the
|
||||
* incoming is cleaned to only match that set.
|
||||
*
|
||||
* @param string $varname The name of the global variable to put the answer in
|
||||
* @param string $match_regex The part of the parameter matching this regex will be returned
|
||||
* @param string $alias1 An alias for the name that we should look for first.
|
||||
* @param " ... More aliases, in the order which they should be examined. $varname will be appended to the end.
|
||||
*/
|
||||
function param_to_global( ) {
|
||||
$args = func_get_args();
|
||||
|
||||
$varname = array_shift($args);
|
||||
$GLOBALS[$varname] = null;
|
||||
|
||||
$match_regex = null;
|
||||
$argc = func_num_args();
|
||||
if ( $argc > 1 ) {
|
||||
$match_regex = array_shift($args);
|
||||
}
|
||||
|
||||
$args[] = $varname;
|
||||
foreach( $args AS $k => $name ) {
|
||||
if ( isset($_POST[$name]) ) {
|
||||
$result = $_POST[$name];
|
||||
break;
|
||||
}
|
||||
else if ( isset($_GET[$name]) ) {
|
||||
$result = $_GET[$name];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !isset($result) ) return null;
|
||||
|
||||
if ( isset($match_regex) ) {
|
||||
$result = check_by_regex( $result, $match_regex );
|
||||
}
|
||||
|
||||
$GLOBALS[$varname] = $result;
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( !function_exists("get_fields") ) {
|
||||
/**
|
||||
* @var array $_AWL_field_cache is a cache of the field names for a table
|
||||
*/
|
||||
$_AWL_field_cache = array();
|
||||
|
||||
/**
|
||||
* Get the names of the fields for a particular table
|
||||
* @param string $tablename The name of the table.
|
||||
* @return array of string The public fields in the table.
|
||||
*/
|
||||
function get_fields( $tablename ) {
|
||||
global $_AWL_field_cache;
|
||||
|
||||
if ( !isset($_AWL_field_cache[$tablename]) ) {
|
||||
dbg_error_log( "core", ":get_fields: Loading fields for table '$tablename'" );
|
||||
$qry = new AwlQuery();
|
||||
$db = $qry->GetConnection();
|
||||
$qry->SetSQL($db->GetFields($tablename));
|
||||
$qry->Exec("core");
|
||||
$fields = array();
|
||||
while( $row = $qry->Fetch() ) {
|
||||
$fields[$row->fieldname] = $row->typename . ($row->precision >= 0 ? sprintf('(%d)',$row->precision) : '');
|
||||
}
|
||||
$_AWL_field_cache[$tablename] = $fields;
|
||||
}
|
||||
return $_AWL_field_cache[$tablename];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( !function_exists("force_utf8") ) {
|
||||
function define_byte_mappings() {
|
||||
global $byte_map, $nibble_good_chars;
|
||||
|
||||
# Needed for using Grant McLean's byte mappings code
|
||||
$ascii_char = '[\x00-\x7F]';
|
||||
$cont_byte = '[\x80-\xBF]';
|
||||
|
||||
$utf8_2 = '[\xC0-\xDF]' . $cont_byte;
|
||||
$utf8_3 = '[\xE0-\xEF]' . $cont_byte . '{2}';
|
||||
$utf8_4 = '[\xF0-\xF7]' . $cont_byte . '{3}';
|
||||
$utf8_5 = '[\xF8-\xFB]' . $cont_byte . '{4}';
|
||||
|
||||
$nibble_good_chars = "/^($ascii_char+|$utf8_2|$utf8_3|$utf8_4|$utf8_5)(.*)$/s";
|
||||
|
||||
# From http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1252.TXT
|
||||
$byte_map = array(
|
||||
"\x80" => "\xE2\x82\xAC", # EURO SIGN
|
||||
"\x82" => "\xE2\x80\x9A", # SINGLE LOW-9 QUOTATION MARK
|
||||
"\x83" => "\xC6\x92", # LATIN SMALL LETTER F WITH HOOK
|
||||
"\x84" => "\xE2\x80\x9E", # DOUBLE LOW-9 QUOTATION MARK
|
||||
"\x85" => "\xE2\x80\xA6", # HORIZONTAL ELLIPSIS
|
||||
"\x86" => "\xE2\x80\xA0", # DAGGER
|
||||
"\x87" => "\xE2\x80\xA1", # DOUBLE DAGGER
|
||||
"\x88" => "\xCB\x86", # MODIFIER LETTER CIRCUMFLEX ACCENT
|
||||
"\x89" => "\xE2\x80\xB0", # PER MILLE SIGN
|
||||
"\x8A" => "\xC5\xA0", # LATIN CAPITAL LETTER S WITH CARON
|
||||
"\x8B" => "\xE2\x80\xB9", # SINGLE LEFT-POINTING ANGLE QUOTATION MARK
|
||||
"\x8C" => "\xC5\x92", # LATIN CAPITAL LIGATURE OE
|
||||
"\x8E" => "\xC5\xBD", # LATIN CAPITAL LETTER Z WITH CARON
|
||||
"\x91" => "\xE2\x80\x98", # LEFT SINGLE QUOTATION MARK
|
||||
"\x92" => "\xE2\x80\x99", # RIGHT SINGLE QUOTATION MARK
|
||||
"\x93" => "\xE2\x80\x9C", # LEFT DOUBLE QUOTATION MARK
|
||||
"\x94" => "\xE2\x80\x9D", # RIGHT DOUBLE QUOTATION MARK
|
||||
"\x95" => "\xE2\x80\xA2", # BULLET
|
||||
"\x96" => "\xE2\x80\x93", # EN DASH
|
||||
"\x97" => "\xE2\x80\x94", # EM DASH
|
||||
"\x98" => "\xCB\x9C", # SMALL TILDE
|
||||
"\x99" => "\xE2\x84\xA2", # TRADE MARK SIGN
|
||||
"\x9A" => "\xC5\xA1", # LATIN SMALL LETTER S WITH CARON
|
||||
"\x9B" => "\xE2\x80\xBA", # SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
|
||||
"\x9C" => "\xC5\x93", # LATIN SMALL LIGATURE OE
|
||||
"\x9E" => "\xC5\xBE", # LATIN SMALL LETTER Z WITH CARON
|
||||
"\x9F" => "\xC5\xB8", # LATIN CAPITAL LETTER Y WITH DIAERESIS
|
||||
);
|
||||
|
||||
for( $i=160; $i < 256; $i++ ) {
|
||||
$ch = chr($i);
|
||||
$byte_map[$ch] = iconv('ISO-8859-1', 'UTF-8', $ch);
|
||||
}
|
||||
}
|
||||
define_byte_mappings();
|
||||
|
||||
function force_utf8( $input ) {
|
||||
global $byte_map, $nibble_good_chars;
|
||||
|
||||
$output = '';
|
||||
$char = '';
|
||||
$rest = '';
|
||||
while( $input != '' ) {
|
||||
if ( preg_match( $nibble_good_chars, $input, $matches ) ) {
|
||||
$output .= $matches[1];
|
||||
$rest = $matches[2];
|
||||
}
|
||||
else {
|
||||
preg_match( '/^(.)(.*)$/s', $input, $matches );
|
||||
$char = $matches[1];
|
||||
$rest = $matches[2];
|
||||
if ( isset($byte_map[$char]) ) {
|
||||
$output .= $byte_map[$char];
|
||||
}
|
||||
else {
|
||||
# Must be valid UTF8 already
|
||||
$output .= $char;
|
||||
}
|
||||
}
|
||||
$input = $rest;
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Try and extract something like "Pacific/Auckland" or "America/Indiana/Indianapolis" if possible.
|
||||
*/
|
||||
function olson_from_tzstring( $tzstring ) {
|
||||
global $c;
|
||||
|
||||
if ( function_exists('timezone_identifiers_list') && in_array($tzstring,timezone_identifiers_list()) ) return $tzstring;
|
||||
if ( preg_match( '{((Antarctica|America|Africa|Atlantic|Asia|Australia|Indian|Europe|Pacific)/(([^/]+)/)?[^/]+)$}', $tzstring, $matches ) ) {
|
||||
// dbg_error_log( 'INFO', 'Found timezone "%s" from string "%s"', $matches[1], $tzstring );
|
||||
return $matches[1];
|
||||
}
|
||||
switch( $tzstring ) {
|
||||
case 'New Zealand Standard Time': case 'New Zealand Daylight Time':
|
||||
return 'Pacific/Auckland';
|
||||
break;
|
||||
case 'Central Standard Time': case 'Central Daylight Time': case 'US/Central':
|
||||
return 'America/Chicago';
|
||||
break;
|
||||
case 'Eastern Standard Time': case 'Eastern Daylight Time': case 'US/Eastern':
|
||||
case '(UTC-05:00) Eastern Time (US & Canada)':
|
||||
return 'America/New_York';
|
||||
break;
|
||||
case 'Pacific Standard Time': case 'Pacific Daylight Time': case 'US/Pacific':
|
||||
return 'America/Los_Angeles';
|
||||
break;
|
||||
case 'Mountain Standard Time': case 'Mountain Daylight Time': case 'US/Mountain': case 'Mountain Time':
|
||||
return 'America/Denver';
|
||||
// The US 'Mountain Time' can in fact be America/(Denver|Boise|Phoenix|Shiprock) which
|
||||
// all vary to some extent due to differing DST rules.
|
||||
break;
|
||||
case '(GMT-07.00) Arizona':
|
||||
return 'America/Phoenix';
|
||||
break;
|
||||
default:
|
||||
if ( isset($c->timezone_translations) && is_array($c->timezone_translations)
|
||||
&& !empty($c->timezone_translations[$tzstring]) )
|
||||
return $c->timezone_translations[$tzstring];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( !function_exists("deprecated") ) {
|
||||
function deprecated( $method ) {
|
||||
global $c;
|
||||
if ( isset($c->dbg['ALL']) || isset($c->dbg['deprecated']) ) {
|
||||
$stack = debug_backtrace();
|
||||
array_shift($stack);
|
||||
if ( preg_match( '{/inc/iCalendar.php$}', $stack[0]['file'] ) && $stack[0]['line'] > __LINE__ ) return;
|
||||
@error_log( sprintf( $c->sysabbr.':DEPRECATED: Call to deprecated method "%s"', $method));
|
||||
foreach( $stack AS $k => $v ) {
|
||||
@error_log( sprintf( $c->sysabbr.': ==> called from line %4d of %s', $v['line'], $v['file']));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( !function_exists("gzdecode") ) {
|
||||
function gzdecode( $instring ) {
|
||||
global $c;
|
||||
if ( !isset($c->use_pipe_gunzip) || $c->use_pipe_gunzip ) {
|
||||
$descriptorspec = array(
|
||||
0 => array("pipe", "r"), // stdin is a pipe that the child will read from
|
||||
1 => array("pipe", "w"), // stdout is a pipe that the child will write to
|
||||
2 => array("file", "/dev/null", "a") // stderr is discarded
|
||||
);
|
||||
$process = proc_open('gunzip',$descriptorspec, $pipes);
|
||||
if ( is_resource($process) ) {
|
||||
fwrite($pipes[0],$instring);
|
||||
fclose($pipes[0]);
|
||||
|
||||
$outstring = stream_get_contents($pipes[1]);
|
||||
fclose($pipes[1]);
|
||||
|
||||
proc_close($process);
|
||||
return $outstring;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
else {
|
||||
$g=tempnam('./','gz');
|
||||
file_put_contents($g,$instring);
|
||||
ob_start();
|
||||
readgzfile($g);
|
||||
$d=ob_get_clean();
|
||||
unlink($g);
|
||||
return $d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the AWL version
|
||||
*/
|
||||
function awl_version() {
|
||||
global $c;
|
||||
$c->awl_library_version = 0.54;
|
||||
return $c->awl_library_version;
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
<?php
|
||||
/**
|
||||
* Functions involved in translating with gettext
|
||||
* @package awl
|
||||
* @subpackage Translation
|
||||
* @author Andrew McMillan <andrew@mcmillan.net.nz>
|
||||
* @copyright Catalyst IT Ltd
|
||||
* @license http://gnu.org/copyleft/gpl.html GNU GPL v2 or later
|
||||
*/
|
||||
|
||||
if ( !function_exists('i18n') ) {
|
||||
/**
|
||||
* Mark a string as being internationalized. This is a semaphore method; it
|
||||
* does nothing but it allows us to easily identify strings that require
|
||||
* translation. Generally this is used to mark strings that will be stored
|
||||
* in the database (like descriptions of permissions).
|
||||
*
|
||||
* AWL uses GNU gettext for internationalization (i18n) and localization (l10n) of
|
||||
* text presented to the user. Gettext needs to know about all places involving strings,
|
||||
* that must be translated. Mark any place, where localization at runtime shall take place
|
||||
* by using the function translate().
|
||||
*
|
||||
* In the help I have used 'xlate' rather than 'translate' and 'x18n' rather than 'i18n'
|
||||
* so that the tools skip this particular file for translation :-)
|
||||
*
|
||||
* E.g. instead of:
|
||||
* print 'TEST to be displayed in different languages';
|
||||
* use:
|
||||
* print xlate('TEST to be displayed in different languages');
|
||||
* and you are all set for pure literals. The translation teams will receive that literal
|
||||
* string as a job to translate and will translate it (when the message is clear enough).
|
||||
* At runtime the message is then localized when printed.
|
||||
* The input string can contain a hint to assist translators:
|
||||
* print xlate('TT <!-- abbreviation for Translation Test -->');
|
||||
* The hint portion of the string will not be printed.
|
||||
*
|
||||
* But consider this case:
|
||||
* $message_to_be_localized = 'TEST to be displayed in different languages';
|
||||
* print xlate($message_to_be_localized);
|
||||
*
|
||||
* The translate() function is called in the right place for runtime handling, but there
|
||||
* is no message at gettext preprocessing time to be given to the translation teams,
|
||||
* just a variable name. Translation of the variable name would break the code! So all
|
||||
* places potentially feeding this variable have to be marked to be given to translation
|
||||
* teams, but not translated at runtime!
|
||||
*
|
||||
* This method resolves all such cases. Simply mark the candidates:
|
||||
* $message_to_be_localized = x18n('TEST to be displayed in different languages');
|
||||
* print xlate($message_to_be_localized);
|
||||
*
|
||||
* @param string the value
|
||||
* @return string the same value
|
||||
*/
|
||||
function i18n($value) {
|
||||
return $value; /* Just pass the value through */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( !function_exists('translate') ) {
|
||||
/**
|
||||
* Convert a string in English to whatever this user's locale is
|
||||
*/
|
||||
if ( function_exists('gettext') ) {
|
||||
function translate( $en ) {
|
||||
if ( ! isset($en) || $en == '' ) return $en;
|
||||
$xl = gettext($en);
|
||||
dbg_error_log('I18N','Translated =%s= into =%s=', $en, $xl );
|
||||
return $xl;
|
||||
}
|
||||
}
|
||||
else {
|
||||
function translate( $en ) {
|
||||
return $en;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( !function_exists('init_gettext') ) {
|
||||
/**
|
||||
* Initialise our use of Gettext
|
||||
*/
|
||||
function init_gettext( $domain, $location ) {
|
||||
if ( !function_exists('bindtextdomain') ) return;
|
||||
bindtextdomain( $domain, $location );
|
||||
$codeset = bind_textdomain_codeset( $domain, 'UTF-8' );
|
||||
textdomain( $domain );
|
||||
dbg_error_log('I18N','Bound domain =%s= to location =%s= using character set =%s=', $domain, $location, $codeset );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( !function_exists('awl_set_locale') ) {
|
||||
/**
|
||||
* Set the translation to the user's locale. At this stage all we do is
|
||||
* call the gettext function.
|
||||
*/
|
||||
function awl_set_locale( $locale ) {
|
||||
global $c;
|
||||
|
||||
if ( !is_array($locale) && ! preg_match('/^[a-z]{2}(_[A-Z]{2})?\./', $locale ) ) {
|
||||
$locale = array( $locale, $locale.'.UTF-8');
|
||||
}
|
||||
if ( !function_exists('setlocale') ) {
|
||||
dbg_log_array('WARN','No "setlocale()" function? PHP gettext support missing?' );
|
||||
return;
|
||||
}
|
||||
if ( $newlocale = setlocale( LC_ALL, $locale) ) {
|
||||
dbg_error_log('I18N','Set locale to =%s=', $newlocale );
|
||||
$c->current_locale = $newlocale;
|
||||
}
|
||||
else {
|
||||
dbg_log_array('I18N','Unsupported locale: ', $locale, false );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,332 @@
|
|||
<?php
|
||||
/**
|
||||
* Handling of namespacing for XML documents
|
||||
*
|
||||
* @package awl
|
||||
* @subpackage XMLDocument
|
||||
* @author Andrew McMillan <andrew@morphoss.com>
|
||||
* @copyright Morphoss Ltd - http://www.morphoss.com/
|
||||
* @license http://www.gnu.org/licenses/lgpl-3.0.txt GNU LGPL version 3 or later
|
||||
*
|
||||
*/
|
||||
|
||||
require_once("XMLElement.php");
|
||||
|
||||
/**
|
||||
* A class for XML Documents which will contain namespaced XML elements
|
||||
*
|
||||
* @package awl
|
||||
*/
|
||||
class XMLDocument {
|
||||
|
||||
/**#@+
|
||||
* @access private
|
||||
*/
|
||||
/**
|
||||
* holds the namespaces which this document has been configured for.
|
||||
* @var namespaces
|
||||
*/
|
||||
private $namespaces;
|
||||
|
||||
/**
|
||||
* holds the prefixes which are shorthand for the namespaces.
|
||||
* @var prefixes
|
||||
*/
|
||||
private $prefixes;
|
||||
|
||||
/**
|
||||
* Holds the root document for the tree
|
||||
* @var root
|
||||
*/
|
||||
private $root;
|
||||
|
||||
/**
|
||||
* Simple XMLDocument constructor
|
||||
*
|
||||
* @param array $namespaces An array of 'namespace' => 'prefix' pairs, where the prefix is used as a short form for the namespace.
|
||||
*/
|
||||
function __construct( $namespaces = null ) {
|
||||
$this->namespaces = array();
|
||||
$this->prefixes = array();
|
||||
if ( $namespaces != null ) {
|
||||
foreach( $namespaces AS $ns => $prefix ) {
|
||||
$this->namespaces[$ns] = $prefix;
|
||||
$this->prefixes[$prefix] = $prefix;
|
||||
}
|
||||
}
|
||||
$this->next_prefix = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new namespace to the document, optionally specifying it's short prefix
|
||||
*
|
||||
* @param string $namespace The full namespace name to be added
|
||||
* @param string $prefix An optional short form for the namespace.
|
||||
*/
|
||||
function AddNamespace( $namespace, $prefix = null ) {
|
||||
if ( !isset($this->namespaces[$namespace]) ) {
|
||||
if ( isset($prefix) && ($prefix == "" || isset($this->prefixes[$prefix])) ) $prefix = null;
|
||||
if ( $prefix == null ) {
|
||||
// Try and build a prefix based on the first alphabetic character of the last element of the namespace
|
||||
if ( preg_match('/^(.*):([^:]+)$/', $namespace, $matches) ) {
|
||||
$alpha = preg_replace( '/[^a-z]/i', '', $matches[2] );
|
||||
$prefix = strtoupper(substr($alpha,0,1));
|
||||
}
|
||||
else {
|
||||
$prefix = 'X';
|
||||
}
|
||||
$i = "";
|
||||
if ( isset($this->prefixes[$prefix]) ) {
|
||||
for ( $i=1; $i<10 && isset($this->prefixes["$prefix$i"]); $i++ ) {
|
||||
}
|
||||
}
|
||||
if ( isset($this->prefixes["$prefix$i"]) ) {
|
||||
dbg_error_log("ERROR", "Cannot find a free prefix for this namespace");
|
||||
exit;
|
||||
}
|
||||
$prefix = "$prefix$i";
|
||||
dbg_error_log("XMLDocument", "auto-assigning prefix of '%s' for ns of '%s'", $prefix, $namespace );
|
||||
}
|
||||
else if ( $prefix == "" || isset($this->prefixes[$prefix]) ) {
|
||||
dbg_error_log("ERROR", "Cannot assign the same prefix to two different namespaces");
|
||||
exit;
|
||||
}
|
||||
|
||||
$this->prefixes[$prefix] = $prefix;
|
||||
$this->namespaces[$namespace] = $prefix;
|
||||
}
|
||||
else {
|
||||
if ( isset($this->namespaces[$namespace]) && $this->namespaces[$namespace] != $prefix ) {
|
||||
dbg_error_log("ERROR", "Cannot use the same namespace with two different prefixes");
|
||||
exit;
|
||||
}
|
||||
$this->prefixes[$prefix] = $prefix;
|
||||
$this->namespaces[$namespace] = $prefix;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default namespace for this document
|
||||
*/
|
||||
function DefaultNamespace() {
|
||||
foreach( $this->namespaces AS $k => $v ) {
|
||||
if ( $v == '' ) {
|
||||
return $k;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a tag with namespace stripped and replaced with a short form, and the ns added to the document.
|
||||
*
|
||||
*/
|
||||
function GetXmlNsArray() {
|
||||
|
||||
$ns = array();
|
||||
foreach( $this->namespaces AS $n => $p ) {
|
||||
if ( $p == "" ) $ns["xmlns"] = $n; else $ns["xmlns:$p"] = $n;
|
||||
}
|
||||
|
||||
return $ns;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a tag with namespace stripped and replaced with a short form, and the ns added to the document.
|
||||
*
|
||||
* @param string $in_tag The tag we want a namespace prefix on.
|
||||
* @param string $namespace The namespace we want it in (which will be parsed from $in_tag if not present
|
||||
* @param string $prefix The prefix we would like to use. Leave it out and one will be assigned.
|
||||
*
|
||||
* @return string The tag with a namespace prefix consistent with previous tags in this namespace.
|
||||
*/
|
||||
function Tag( $in_tag, $namespace=null, $prefix=null ) {
|
||||
|
||||
if ( $namespace == null ) {
|
||||
// Attempt to split out from namespace:tag
|
||||
if ( preg_match('/^(.*):([^:]+)$/', $in_tag, $matches) ) {
|
||||
$namespace = $matches[1];
|
||||
$tag = $matches[2];
|
||||
}
|
||||
else {
|
||||
// There is nothing we can do here
|
||||
return $in_tag;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$tag = $in_tag;
|
||||
}
|
||||
|
||||
if ( !isset($this->namespaces[$namespace]) ) {
|
||||
$this->AddNamespace( $namespace, $prefix );
|
||||
}
|
||||
$prefix = $this->namespaces[$namespace];
|
||||
|
||||
return $prefix . ($prefix == "" ? "" : ":") . $tag;
|
||||
}
|
||||
|
||||
static public $ns_dav = 'DAV:';
|
||||
static public $ns_caldav = 'urn:ietf:params:xml:ns:caldav';
|
||||
static public $ns_carddav = 'urn:ietf:params:xml:ns:carddav';
|
||||
static public $ns_calendarserver = 'http://calendarserver.org/ns/';
|
||||
|
||||
/**
|
||||
* Special helper for namespaced tags.
|
||||
*
|
||||
* @param object $element The tag are adding a new namespaced element to
|
||||
* @param string $tag the tag name, possibly prefixed with the namespace
|
||||
* @param mixed $content The content of the tag
|
||||
* @param array $attributes An array of key/value pairs of attributes.
|
||||
* @param string $namespace The namespace for the tag
|
||||
*
|
||||
*/
|
||||
function NSElement( &$element, $in_tag, $content=false, $attributes=false, $namespace=null ) {
|
||||
if ( $namespace == null && preg_match('/^(.*):([^:]+)$/', $in_tag, $matches) ) {
|
||||
$namespace = $matches[1];
|
||||
if ( preg_match('{^[A-Z][A-Z0-9]*$}', $namespace ) ) {
|
||||
throw new Exception("Dodgy looking namespace from '".$in_tag."'!");
|
||||
}
|
||||
$tag = $matches[2];
|
||||
}
|
||||
else {
|
||||
$tag = $in_tag;
|
||||
if ( isset($namespace) ) {
|
||||
$tag = str_replace($namespace.':', '', $tag);
|
||||
}
|
||||
}
|
||||
|
||||
if ( isset($namespace) && !isset($this->namespaces[$namespace]) ) $this->AddNamespace( $namespace );
|
||||
return $element->NewElement( $tag, $content, $attributes, $namespace );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Special helper for tags in the DAV: namespace.
|
||||
*
|
||||
* @param object $element The tag are adding a new namespaced element to
|
||||
* @param string $tag the tag name
|
||||
* @param mixed $content The content of the tag
|
||||
* @param array $attributes An array of key/value pairs of attributes.
|
||||
*/
|
||||
function DAVElement( &$element, $tag, $content=false, $attributes=false ) {
|
||||
if ( !isset($this->namespaces[self::$ns_dav]) ) $this->AddNamespace( self::$ns_dav, '' );
|
||||
return $this->NSElement( $element, $tag, $content, $attributes, self::$ns_dav );
|
||||
}
|
||||
|
||||
/**
|
||||
* Special helper for tags in the urn:ietf:params:xml:ns:caldav namespace.
|
||||
*
|
||||
* @param object $element The tag are adding a new namespaced element to
|
||||
* @param string $tag the tag name
|
||||
* @param mixed $content The content of the tag
|
||||
* @param array $attributes An array of key/value pairs of attributes.
|
||||
*/
|
||||
function CalDAVElement( &$element, $tag, $content=false, $attributes=false ) {
|
||||
if ( !isset($this->namespaces[self::$ns_caldav]) ) $this->AddNamespace( self::$ns_caldav, 'C' );
|
||||
return $this->NSElement( $element, $tag, $content, $attributes, self::$ns_caldav );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Special helper for tags in the urn:ietf:params:xml:ns:carddav namespace.
|
||||
*
|
||||
* @param object $element The tag are adding a new namespaced element to
|
||||
* @param string $tag the tag name
|
||||
* @param mixed $content The content of the tag
|
||||
* @param array $attributes An array of key/value pairs of attributes.
|
||||
*/
|
||||
function CardDAVElement( &$element, $tag, $content=false, $attributes=false ) {
|
||||
if ( !isset($this->namespaces[self::$ns_carddav]) ) $this->AddNamespace( self::$ns_carddav, 'VC' );
|
||||
return $this->NSElement( $element, $tag, $content, $attributes, self::$ns_carddav );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Special helper for tags in the urn:ietf:params:xml:ns:caldav namespace.
|
||||
*
|
||||
* @param object $element The tag are adding a new namespaced element to
|
||||
* @param string $tag the tag name
|
||||
* @param mixed $content The content of the tag
|
||||
* @param array $attributes An array of key/value pairs of attributes.
|
||||
*/
|
||||
function CalendarserverElement( &$element, $tag, $content=false, $attributes=false ) {
|
||||
if ( !isset($this->namespaces[self::$ns_calendarserver]) ) $this->AddNamespace( self::$ns_calendarserver, 'A' );
|
||||
return $this->NSElement( $element, $tag, $content, $attributes, self::$ns_calendarserver );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $in_tag The tag name of the new element, possibly namespaced
|
||||
* @param mixed $content Either a string of content, or an array of sub-elements
|
||||
* @param array $attributes An array of attribute name/value pairs
|
||||
* @param array $xmlns An XML namespace specifier
|
||||
*/
|
||||
function NewXMLElement( $in_tag, $content=false, $attributes=false, $xmlns=null ) {
|
||||
if ( $xmlns == null && preg_match('/^(.*):([^:]+)$/', $in_tag, $matches) ) {
|
||||
$xmlns = $matches[1];
|
||||
$tagname = $matches[2];
|
||||
}
|
||||
else {
|
||||
$tagname = $in_tag;
|
||||
}
|
||||
|
||||
if ( isset($xmlns) && !isset($this->namespaces[$xmlns]) ) $this->AddNamespace( $xmlns );
|
||||
return new XMLElement($tagname, $content, $attributes, $xmlns );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the document tree into (nicely formatted) XML
|
||||
*
|
||||
* @param mixed $root A root XMLElement or a tagname to create one with the remaining parameters.
|
||||
* @param mixed $content Either a string of content, or an array of sub-elements
|
||||
* @param array $attributes An array of attribute name/value pairs
|
||||
* @param array $xmlns An XML namespace specifier
|
||||
*
|
||||
* @return A rendered namespaced XML document.
|
||||
*/
|
||||
function Render( $root, $content=false, $attributes=false, $xmlns=null ) {
|
||||
if ( is_object($root) ) {
|
||||
/** They handed us a pre-existing object. We'll just use it... */
|
||||
$this->root = $root;
|
||||
}
|
||||
else {
|
||||
/** We got a tag name, so we need to create the root element */
|
||||
$this->root = $this->NewXMLElement( $root, $content, $attributes, $xmlns );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add our namespace attributes here.
|
||||
*/
|
||||
foreach( $this->namespaces AS $n => $p ) {
|
||||
$this->root->SetAttribute( 'xmlns'.($p == '' ? '' : ':') . $p, $n);
|
||||
}
|
||||
|
||||
/** And render... */
|
||||
return $this->root->Render(0,'<?xml version="1.0" encoding="utf-8" ?>');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a DAV::href XML element, or an array of them
|
||||
* @param mixed $url The URL (or array of URLs) to be wrapped in DAV::href tags
|
||||
*
|
||||
* @return XMLElement The newly created XMLElement object.
|
||||
*/
|
||||
function href($url) {
|
||||
if ( is_array($url) ) {
|
||||
$set = array();
|
||||
foreach( $url AS $href ) {
|
||||
$set[] = $this->href( $href );
|
||||
}
|
||||
return $set;
|
||||
}
|
||||
if ( preg_match('[@+ ]',$url) ) {
|
||||
trace_bug('URL "%s" was not encoded before call to XMLDocument::href()', $url );
|
||||
$url = str_replace( '%2F', '/', rawurlencode($url));
|
||||
}
|
||||
return $this->NewXMLElement('href', $url, false, 'DAV:');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,383 @@
|
|||
<?php
|
||||
/**
|
||||
* A class to assist with construction of XML documents
|
||||
*
|
||||
* @package awl
|
||||
* @subpackage XMLElement
|
||||
* @author Andrew McMillan <andrew@mcmillan.net.nz>
|
||||
* @copyright Catalyst .Net Ltd, Morphoss Ltd <http://www.morphoss.com/>
|
||||
* @license http://www.gnu.org/licenses/lgpl-3.0.txt GNU LGPL version 3 or later
|
||||
*/
|
||||
|
||||
require_once('AWLUtilities.php');
|
||||
|
||||
/**
|
||||
* A class for XML elements which may have attributes, or contain
|
||||
* other XML sub-elements
|
||||
*
|
||||
* @package awl
|
||||
*/
|
||||
class XMLElement {
|
||||
protected $tagname;
|
||||
protected $xmlns;
|
||||
protected $attributes;
|
||||
protected $content;
|
||||
protected $_parent;
|
||||
|
||||
/**
|
||||
* Constructor - nothing fancy as yet.
|
||||
*
|
||||
* @param string $tagname The tag name of the new element
|
||||
* @param mixed $content Either a string of content, or an array of sub-elements
|
||||
* @param array $attributes An array of attribute name/value pairs
|
||||
* @param string $xmlns An XML namespace specifier
|
||||
*/
|
||||
function __construct( $tagname, $content=false, $attributes=false, $xmlns=null ) {
|
||||
$this->tagname=$tagname;
|
||||
if ( gettype($content) == "object" ) {
|
||||
// Subtree to be parented here
|
||||
$this->content = array(&$content);
|
||||
}
|
||||
else {
|
||||
// Array or text
|
||||
$this->content = $content;
|
||||
}
|
||||
$this->attributes = $attributes;
|
||||
if ( isset($xmlns) ) {
|
||||
$this->xmlns = $xmlns;
|
||||
}
|
||||
else {
|
||||
if ( preg_match( '{^(.*):([^:]*)$}', $tagname, $matches) ) {
|
||||
$prefix = $matches[1];
|
||||
$tag = $matches[2];
|
||||
if ( isset($this->attributes['xmlns:'.$prefix]) ) {
|
||||
$this->xmlns = $this->attributes['xmlns:'.$prefix];
|
||||
}
|
||||
}
|
||||
else if ( isset($this->attributes['xmlns']) ) {
|
||||
$this->xmlns = $this->attributes['xmlns'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Count the number of elements
|
||||
* @return int The number of elements
|
||||
*/
|
||||
function CountElements( ) {
|
||||
if ( $this->content === false ) return 0;
|
||||
if ( is_array($this->content) ) return count($this->content);
|
||||
if ( $this->content == '' ) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an element attribute to a value
|
||||
*
|
||||
* @param string The attribute name
|
||||
* @param string The attribute value
|
||||
*/
|
||||
function SetAttribute($k,$v) {
|
||||
if ( gettype($this->attributes) != "array" ) $this->attributes = array();
|
||||
$this->attributes[$k] = $v;
|
||||
if ( strtolower($k) == 'xmlns' ) {
|
||||
$this->xmlns = $v;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the whole content to a value
|
||||
*
|
||||
* @param mixed The element content, which may be text, or an array of sub-elements
|
||||
*/
|
||||
function SetContent($v) {
|
||||
$this->content = $v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for the tag name
|
||||
*
|
||||
* @return string The tag name of the element
|
||||
*/
|
||||
function GetTag() {
|
||||
return $this->tagname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for the full-namespaced tag name
|
||||
*
|
||||
* @return string The tag name of the element, prefixed by the namespace
|
||||
*/
|
||||
function GetNSTag() {
|
||||
return (empty($this->xmlns) ? '' : $this->xmlns . ':') . $this->tagname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for a single attribute
|
||||
* @param string $attr The name of the attribute.
|
||||
* @return string The value of that attribute of the element
|
||||
*/
|
||||
function GetAttribute( $attr ) {
|
||||
if ( $attr == 'xmlns' ) return $this->xmlns;
|
||||
if ( isset($this->attributes[$attr]) ) return $this->attributes[$attr];
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for the attributes
|
||||
*
|
||||
* @return array The attributes of this element
|
||||
*/
|
||||
function GetAttributes() {
|
||||
return $this->attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for the content
|
||||
*
|
||||
* @return array The content of this element
|
||||
*/
|
||||
function GetContent() {
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of elements matching the specified tag, or all elements if no tag is supplied.
|
||||
* Unlike GetContent() this will always return an array.
|
||||
*
|
||||
* @return array The XMLElements within the tree which match this tag
|
||||
*/
|
||||
function GetElements( $tag=null, $recursive=false ) {
|
||||
$elements = array();
|
||||
if ( gettype($this->content) == "array" ) {
|
||||
foreach( $this->content AS $k => $v ) {
|
||||
if ( empty($tag) || $v->GetNSTag() == $tag ) {
|
||||
$elements[] = $v;
|
||||
}
|
||||
if ( $recursive ) {
|
||||
$elements = $elements + $v->GetElements($tag,true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( empty($tag) || (isset($v->content->tagname) && $v->content->GetNSTag() == $tag) ) {
|
||||
$elements[] = $this->content;
|
||||
}
|
||||
return $elements;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return an array of elements matching the specified path
|
||||
*
|
||||
* @return array The XMLElements within the tree which match this tag
|
||||
*/
|
||||
function GetPath( $path ) {
|
||||
$elements = array();
|
||||
// printf( "Querying within '%s' for path '%s'\n", $this->tagname, $path );
|
||||
if ( !preg_match( '#(/)?([^/]+)(/?.*)$#', $path, $matches ) ) return $elements;
|
||||
// printf( "Matches: %s -- %s -- %s\n", $matches[1], $matches[2], $matches[3] );
|
||||
if ( $matches[2] == '*' || $matches[2] == $this->GetNSTag()) {
|
||||
if ( $matches[3] == '' ) {
|
||||
/**
|
||||
* That is the full path
|
||||
*/
|
||||
$elements[] = $this;
|
||||
}
|
||||
else if ( gettype($this->content) == "array" ) {
|
||||
/**
|
||||
* There is more to the path, so we recurse into that sub-part
|
||||
*/
|
||||
foreach( $this->content AS $k => $v ) {
|
||||
$elements = array_merge( $elements, $v->GetPath($matches[3]) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $matches[1] != '/' && gettype($this->content) == "array" ) {
|
||||
/**
|
||||
* If our input $path was not rooted, we recurse further
|
||||
*/
|
||||
foreach( $this->content AS $k => $v ) {
|
||||
$elements = array_merge( $elements, $v->GetPath($path) );
|
||||
}
|
||||
}
|
||||
// printf( "Found %d within '%s' for path '%s'\n", count($elements), $this->tagname, $path );
|
||||
return $elements;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a sub-element
|
||||
*
|
||||
* @param object An XMLElement to be appended to the array of sub-elements
|
||||
*/
|
||||
function AddSubTag(&$v) {
|
||||
if ( gettype($this->content) != "array" ) $this->content = array();
|
||||
$this->content[] =& $v;
|
||||
return count($this->content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new sub-element
|
||||
*
|
||||
* @param string The tag name of the new element
|
||||
* @param mixed Either a string of content, or an array of sub-elements
|
||||
* @param array An array of attribute name/value pairs
|
||||
*
|
||||
* @return objectref A reference to the new XMLElement
|
||||
*/
|
||||
function &NewElement( $tagname, $content=false, $attributes=false, $xmlns=null ) {
|
||||
if ( gettype($this->content) != "array" ) $this->content = array();
|
||||
$element = new XMLElement($tagname,$content,$attributes,$xmlns);
|
||||
$this->content[] =& $element;
|
||||
return $element;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Render just the internal content
|
||||
*
|
||||
* @return string The content of this element, as a string without this element wrapping it.
|
||||
*/
|
||||
function RenderContent($indent=0, $nslist=null, $force_xmlns=false ) {
|
||||
$r = "";
|
||||
if ( is_array($this->content) ) {
|
||||
/**
|
||||
* Render the sub-elements with a deeper indent level
|
||||
*/
|
||||
$r .= "\n";
|
||||
foreach( $this->content AS $k => $v ) {
|
||||
if ( is_object($v) ) {
|
||||
$r .= $v->Render($indent+1, "", $nslist, $force_xmlns);
|
||||
}
|
||||
}
|
||||
$r .= substr(" ",0,$indent);
|
||||
}
|
||||
else {
|
||||
/**
|
||||
* Render the content, with special characters escaped
|
||||
*
|
||||
*/
|
||||
if(strpos($this->content, '<![CDATA[')===0 && strrpos($this->content, ']]>')===strlen($this->content)-3)
|
||||
$r .= '<![CDATA[' . str_replace(']]>', ']]]]><![CDATA[>', substr($this->content, 9, -3)) . ']]>';
|
||||
else if ( defined('ENT_XML1') && defined('ENT_DISALLOWED') )
|
||||
// Newer PHP versions allow specifying ENT_XML1, but default to ENT_HTML401. Go figure. #PHPWTF
|
||||
$r .= htmlspecialchars($this->content, ENT_NOQUOTES | ENT_XML1 | ENT_DISALLOWED );
|
||||
// Need to work out exactly how to do this in PHP.
|
||||
// else if ( preg_match('{^[\t\n\r\x0020-\xD7FF\xE000-\xFFFD\x10000-\x10FFFF]+$}u', utf8ToUnicode($this->content)) )
|
||||
// $r .= '<![CDATA[' . $this->content . ']]>';
|
||||
else
|
||||
// Older PHP versions default to ENT_XML1.
|
||||
$r .= htmlspecialchars($this->content, ENT_NOQUOTES );
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Render the document tree into (nicely formatted) XML
|
||||
*
|
||||
* @param int The indenting level for the pretty formatting of the element
|
||||
*/
|
||||
function Render($indent=0, $xmldef="", $nslist=null, $force_xmlns=false) {
|
||||
$r = ( $xmldef == "" ? "" : $xmldef."\n");
|
||||
|
||||
$attr = "";
|
||||
$tagname = $this->tagname;
|
||||
$xmlns_done = false;
|
||||
if ( gettype($this->attributes) == "array" ) {
|
||||
/**
|
||||
* Render the element attribute values
|
||||
*/
|
||||
foreach( $this->attributes AS $k => $v ) {
|
||||
if ( preg_match('#^xmlns(:?(.+))?$#', $k, $matches ) ) {
|
||||
// if ( $force_xmlns ) printf( "1: %s: %s\n", $this->tagname, $this->xmlns );
|
||||
if ( !isset($nslist) ) $nslist = array();
|
||||
$prefix = (isset($matches[2]) ? $matches[2] : '');
|
||||
if ( isset($nslist[$v]) && $nslist[$v] == $prefix ) continue; // No need to include in list as it's in a wrapping element
|
||||
$nslist[$v] = $prefix;
|
||||
if ( !isset($this->xmlns) ) $this->xmlns = $v;
|
||||
$xmlns_done = true;
|
||||
}
|
||||
$attr .= sprintf( ' %s="%s"', $k, htmlspecialchars($v) );
|
||||
}
|
||||
}
|
||||
if ( isset($this->xmlns) && isset($nslist[$this->xmlns]) && $nslist[$this->xmlns] != '' ) {
|
||||
// if ( $force_xmlns ) printf( "2: %s: %s\n", $this->tagname, $this->xmlns );
|
||||
$tagname = $nslist[$this->xmlns] . ':' . $tagname;
|
||||
if ( $force_xmlns ) $attr .= sprintf( ' xmlns="%s"', $this->xmlns);
|
||||
}
|
||||
else if ( isset($this->xmlns) && !isset($nslist[$this->xmlns]) && gettype($this->attributes) == 'array' && !isset($this->attributes[$this->xmlns]) ) {
|
||||
// if ( $force_xmlns ) printf( "3: %s: %s\n", $this->tagname, $this->xmlns );
|
||||
$attr .= sprintf( ' xmlns="%s"', $this->xmlns);
|
||||
}
|
||||
else if ( $force_xmlns && isset($this->xmlns) && ! $xmlns_done ) {
|
||||
// printf( "4: %s: %s\n", $this->tagname, $this->xmlns );
|
||||
$attr .= sprintf( ' xmlns="%s"', $this->xmlns);
|
||||
}
|
||||
|
||||
$r .= substr(" ",0,$indent) . '<' . $tagname . $attr;
|
||||
|
||||
if ( (is_array($this->content) && count($this->content) > 0) || (!is_array($this->content) && strlen($this->content) > 0) ) {
|
||||
$r .= ">";
|
||||
$r .= $this->RenderContent($indent,$nslist,$force_xmlns);
|
||||
$r .= '</' . $tagname.">\n";
|
||||
}
|
||||
else {
|
||||
$r .= "/>\n";
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
|
||||
function __tostring() {
|
||||
return $this->Render();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Rebuild an XML tree in our own style from the parsed XML tags using
|
||||
* a tail-recursive approach.
|
||||
*
|
||||
* @param array $xmltags An array of XML tags we get from using the PHP XML parser
|
||||
* @param intref &$start_from A pointer to our current integer offset into $xmltags
|
||||
* @return mixed Either a single XMLElement, or an array of XMLElement objects.
|
||||
*/
|
||||
function BuildXMLTree( $xmltags, &$start_from ) {
|
||||
$content = array();
|
||||
|
||||
if ( !isset($start_from) ) $start_from = 0;
|
||||
|
||||
for( $i=0; $i < 50000 && isset($xmltags[$start_from]); $i++) {
|
||||
$tagdata = $xmltags[$start_from++];
|
||||
if ( !isset($tagdata) || !isset($tagdata['tag']) || !isset($tagdata['type']) ) break;
|
||||
if ( $tagdata['type'] == "close" ) break;
|
||||
$xmlns = null;
|
||||
$tag = $tagdata['tag'];
|
||||
if ( preg_match( '{^(.*):([^:]*)$}', $tag, $matches) ) {
|
||||
$xmlns = $matches[1];
|
||||
$tag = $matches[2];
|
||||
}
|
||||
$attributes = ( isset($tagdata['attributes']) ? $tagdata['attributes'] : false );
|
||||
if ( $tagdata['type'] == "open" ) {
|
||||
$subtree = BuildXMLTree( $xmltags, $start_from );
|
||||
$content[] = new XMLElement($tag, $subtree, $attributes, $xmlns );
|
||||
}
|
||||
else if ( $tagdata['type'] == "complete" ) {
|
||||
$value = ( isset($tagdata['value']) ? $tagdata['value'] : false );
|
||||
$content[] = new XMLElement($tag, $value, $attributes, $xmlns );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If there is only one element, return it directly, otherwise return the
|
||||
* array of them
|
||||
*/
|
||||
if ( count($content) == 1 ) {
|
||||
return $content[0];
|
||||
}
|
||||
return $content;
|
||||
}
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
<?php
|
||||
|
||||
require_once('../SimpleCalDAVClient.php');
|
||||
|
||||
$firstNewEvent = 'BEGIN:VCALENDAR
|
||||
PRODID:-//Atelier Lalis//FR
|
||||
VERSION:2.0
|
||||
BEGIN:VTIMEZONE
|
||||
TZID:Europe/Paris
|
||||
X-LIC-LOCATION:Europe/Paris
|
||||
BEGIN:DAYLIGHT
|
||||
TZOFFSETFROM:+0100
|
||||
TZOFFSETTO:+0200
|
||||
TZNAME:CEST
|
||||
DTSTART:19700329T020000
|
||||
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=3
|
||||
END:DAYLIGHT
|
||||
BEGIN:STANDARD
|
||||
TZOFFSETFROM:+0200
|
||||
TZOFFSETTO:+0100
|
||||
TZNAME:CET
|
||||
DTSTART:19701025T030000
|
||||
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
|
||||
END:STANDARD
|
||||
END:VTIMEZONE
|
||||
BEGIN:VEVENT
|
||||
CREATED:[date_creation]
|
||||
LAST-MODIFIED:[date_creation]
|
||||
DTSTAMP:[date_creation]
|
||||
UID:Atelier[UID]
|
||||
CATEGORIES:Lalis, ateliers
|
||||
CLASS:PUBLIC
|
||||
SUMMARY:Atelier du [date]
|
||||
DTSTART;TZID=Europe/Paris:[datetime_start]
|
||||
DTEND;TZID=Europe/Paris:[datetime_stop]
|
||||
LOCATION:Lalis 7 place Louis Chazette 69001 Lyon
|
||||
DESCRIPTION:Atelier Lalis\nInscription: [url]
|
||||
END:VEVENT
|
||||
END:VCALENDAR';
|
||||
|
||||
|
||||
$client = new SimpleCalDAVClient();
|
||||
|
||||
try {
|
||||
/*
|
||||
* To establish a connection and to choose a calendar on the server, use
|
||||
* connect()
|
||||
* findCalendars()
|
||||
* setCalendar()
|
||||
*/
|
||||
|
||||
$client->connect('https://https://lalis69.ddns.net:10443/laliscloud/remote.php/dav/principals/users/DTux/', 'lalis', 'Lalis69_cloud');
|
||||
|
||||
$arrayOfCalendars = $client->findCalendars(); // Returns an array of all accessible calendars on the server.
|
||||
|
||||
$client->setCalendar($arrayOfCalendars["myCalendarID"]); // Here: Use the calendar ID of your choice. If you don't know which calendar ID to use, try config/listCalendars.php
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* You can create calendar objects (e.g. events, todos,...) on the server with create().
|
||||
* Just pass a string with the iCalendar-data which should be saved on the server.
|
||||
* The function returns a CalDAVObject (see CalDAVObject.php) with the stored information about the new object on the server
|
||||
*/
|
||||
|
||||
$firstNewEventOnServer = $client->create($firstNewEvent); // Creates $firstNewEvent on the server and a CalDAVObject representing the event.
|
||||
$secondNewEventOnServer = $client->create($secondNewEvent); // Creates $firstNewEvent on the server and a CalDAVObject representing the event.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* You can getEvents with getEvents()
|
||||
*/
|
||||
$client->getEvents('20140418T103000Z', '20140419T200000Z'); // Returns array($firstNewEventOnServer, $secondNewEventOnServer);
|
||||
|
||||
/*
|
||||
* An CalDAVObject $o has three attributes
|
||||
* $o->getHref(): Link to the object on the server
|
||||
* $o->getData(): The iCalendar-data describing the object
|
||||
* $o->getEtag(): see CalDAVObject.php
|
||||
*
|
||||
* $o->getHref() and $o->getEtag() can be used to change or to delete the object.
|
||||
* $o->getData() can be processed further on, e.g. printed
|
||||
*/
|
||||
|
||||
$firstNewEventOnServer = $client->change($firstNewEventOnServer->getHref(),$changedFirstEvent, $firstNewEventOnServer->getEtag());
|
||||
// Change the first event on the server from $firstNewEvent to $changedFirstEvent
|
||||
// and overwrite $firstNewEventOnServer with the new representation of the changed event on the server.
|
||||
|
||||
$events = $client->getEvents('20140418T103000Z', '20140419T200000Z'); // Returns array($secondNewEventOnServer);
|
||||
|
||||
echo $events[0]->getData(); // Prints $secondNewEvent. See CalDAVObject.php
|
||||
|
||||
$client->delete($secondNewEventOnServer->getHref(), $secondNewEventOnServer->getEtag()); // Deletes the second new event from the server.
|
||||
|
||||
$client->getEvents('20140418T103000Z', '20140419T200000Z'); // Returns an empty array
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* You can create custom queries to the server via CalDAVFilter. See CalDAVFilter.php
|
||||
*/
|
||||
|
||||
$filter = new CalDAVFilter("VEVENT");
|
||||
$filter->mustInclude("SUMMARY"); // Should include a SUMMARY
|
||||
$filter->mustInclude("PRIORITY", TRUE); // Should not include a PRIORITY
|
||||
$filter->mustIncludeMatchSubstr("DESCRIPTION", "ExampleDescription2", TRUE); // "ExampleDescription1" should not be a substring of the DESCRIPTION
|
||||
$filter->mustOverlapWithTimerange(NULL, "20140420T100000Z");
|
||||
$events = $client->getCustomReport($filter->toXML()); // Returns array($changedFirstEvent)
|
||||
|
||||
$client->delete($events[0]->getHref(), $events[0]->getEtag()); // Deletes the changed first event from the server.
|
||||
}
|
||||
|
||||
catch (Exception $e) {
|
||||
echo $e->__toString();
|
||||
}
|
||||
|
||||
?>
|
Reference in New Issue