LOGFILE_CLIENTMESSAGE
LOGFILE_CLIENTMESSAGE
Types of logfiles. See logFile() method.
A SyncML Backend provides the interface between the SyncML protocol and an actual calendar or address book application. This "actual application" is called the "data store" in this description.
The backend provides the following groups of functions:
1) Access to the datastore Reading, adding, replacing and deleting of entries. Also retrieve information about changes in data store. This is done via the retrieveEntry(), addEntry(), replaceEntry(), deleteEntry() and getServerChanges() methods.
2) User management functions This is the checkAuthentication() method to verify that a given user password combination is allowed to access the backend data store, and the setUser() method which does a "login" to the backend data store if required by the type of backend data store. Please note that the password is only transferred once in a sync session, so when handling the subsequent packets messages, the user may need to be "logged in" without a password. (Or the session management keeps the user "logged in").
3) Maintainig the client ID <-> server ID map The SyncML protocol does not require clients and servers to use the same primary keys for the data entries. So a map has to be in place to convert between client primary keys (called cuid's here) and server primary keys (called suid's). It's up to the server to maintain this map. Method for this is createUidMap().
4) Sync anchor handling After a successful initial sync, the client and server sync timestamps are stored. This allows to perform subsequent syncs as delta syncs, where only new changes are replicated. Servers as well as clients need to be able to store two sync anchors (the client's and the server's) for a sync. Methods for this are readSyncAnchors() and writeSyncAnchors().
5) Test supporting functions The SyncML module comes with its own testing framework. All you need to do is implement the two methods testSetup() and testTearDown() and you are able to test your backend with all the test cases that are part of the module.
6) Miscellaneous functions This involves session handling (sessionStart() and sessionClose()), logging (logMessage() and logFile()), timestamp creation (getCurrentTimeStamp()), charset handling (getCharset(), setCharset()) and database identification (isValidDatabaseURI()). For all of these functions, a default implementation is provided in Horde_SyncMl_Backend.
If you want to create a backend for your own appliction, you can either derive from Horde_SyncMl_Backend and implement everything in groups 1 to 5 or you derive from Horde_SyncMl_Backend_Sql which implements an example backend based on direct database access using the PEAR MDB2 package. In this case you only need to implement groups 1 to 3 and can use the implementation from Horde_SyncMl_Backend_Sql as a guideline for these functions.
In order to successfully create a backend, some understanding of a few key concepts in SyncML and the Horde_SyncMl package are certainly helpful. So here's some stuff that should make some issues clear (or at lest less obfuscated):
1) DatabaseURIs and Databases
The SyncML protocol itself is completly independant from the data that
is replicated. Normally the data are calendar or address book entries
but it may really be anything from browser bookmarks to comeplete
database tables. An ID (string name) of the database you want to
actually replicate has to be configured in the client. Typically that's
something like 'calendar' or 'tasks'. Client and server must agree on
these names. In addition this string may be used to provide additional
arguments. These are provided in a HTTP GET query style: like
tasks?ignorecompletedtasks to replicate only pending tasks. Such a "sync
identifier" is called a DatabaseURI and is really a database name plus
some additional options.
The Horde_SyncMl package completly ignores these options and simply passes
them on to the backend. It's up to the backend to decide what to do with
them. However when dealing with the internal maps (cuid<->suid and sync
anchors), it's most likely to use the database name only rather than the
full databaseURI. The map information saying that server entry
20070101203040xxa@mypc.org has id 768 in the client device is valid for
the database "tasks", not for "tasks?somesillyoptions". So what you
normally do is calling some kind of $database =
$this->normalize($databaseURI) in every backend method that deals
with databaseURIs and use $database afterwards. However actual usage of
options is up to the backend implementation. SyncML works fine without.
2) Suid and Guid mapping This is the mapping of client IDs to server IDs and vice versa. Please note that this map is per user and per client device: the server entry 20070101203040xxa@mypc.org may have ID 720 in your PDA and AA10FC3A in your mobile phone.
3) Sync Anchors
$state : \Horde_SyncMl_State
The State object.
factory(string $driver, array $params = null) : \Horde_SyncMl_Backend
Attempts to return a concrete Horde_SyncMl_Backend instance based on $driver.
string | $driver | The type of concrete Backend subclass to return. The code is dynamically included from Backend/$driver.php if no path is given or directly with "include_once $driver . '.php'" if a path is included. So make sure this parameter is "safe" and not directly taken from web input. The class in the file must be named 'Horde_SyncMlBackend' . basename($driver) and extend Horde_SyncMl_Backend. |
array | $params | A hash containing any additional configuration or connection parameters a subclass might need. |
The newly created concrete Horde_SyncMl_Backend instance, or false on an error.
setUser(string $user)
Sets the user used for this session.
This method is called by SyncML right after sessionStart() when either authentication is accepted via checkAuthentication() or a valid user has been retrieved from the state. $this->_user together with $this->_syncDeviceID is used as an additional key for all persistence operations. This method may have to force a "login", when the backend doesn't keep auth state within a session or when in test mode.
string | $user | A user name. |
isValidDatabaseURI(string $databaseURI) : boolean
Returns whether a database URI is valid to be synced with this backend.
This default implementation accepts "tasks", "calendar", "notes" and "contacts". However individual backends may offer replication of different or completly other databases (like browser bookmarks or cooking recipes).
string | $databaseURI | URI of a database. Like calendar, tasks, contacts or notes. May include optional parameters: tasks?options=ignorecompleted. |
True if a valid URI.
getServerChanges(string $databaseURI, integer $from_ts, integer $to_ts, $adds, $mods, $dels) : mixed
Returns entries that have been modified in the server database.
string | $databaseURI | URI of Database to sync. Like calendar, tasks, contacts or notes. May include optional parameters: tasks?options=ignorecompleted. |
integer | $from_ts | Start timestamp. |
integer | $to_ts | Exclusive end timestamp. Not yet implemented. |
$adds | ||
$mods | ||
$dels |
True on success or a PEAR_Error object.
retrieveEntry(string $databaseURI, string $suid, string $contentType, array $fields) : mixed
Retrieves an entry from the backend.
string | $databaseURI | URI of Database to sync. Like calendar, tasks, contacts or notes. May include optional parameters: tasks?options=ignorecompleted. |
string | $suid | Server unique id of the entry: for horde this is the guid. |
string | $contentType | Content-Type: the MIME type in which the public function should return the data. |
array | $fields | Hash of field names and Horde_SyncMl_Property properties with the requested fields. |
A string with the data entry or a PEAR_Error object.
addEntry(string $databaseURI, string $content, string $contentType, string $cuid = null) : array
Adds an entry into the server database.
string | $databaseURI | URI of Database to sync. Like calendar, tasks, contacts or notes. May include optional parameters: tasks?options=ignorecompleted. |
string | $content | The actual data. |
string | $contentType | MIME type of the content. |
string | $cuid | Client ID of this entry. |
PEAR_Error or suid (Horde guid) of new entry
replaceEntry(string $databaseURI, string $content, string $contentType, string $cuid) : string
Replaces an entry in the server database.
string | $databaseURI | URI of Database to sync. Like calendar, tasks, contacts or notes. May include optional parameters: tasks?options=ignorecompleted. |
string | $content | The actual data. |
string | $contentType | MIME type of the content. |
string | $cuid | Client ID of this entry. |
PEAR_Error or server ID (Horde GUID) of modified entry.
deleteEntry(string $databaseURI, string $cuid) : boolean
Deletes an entry from the server database.
string | $databaseURI | URI of Database to sync. Like calendar, tasks, contacts or notes. May include optional parameters: tasks?options=ignorecompleted. |
string | $cuid | Client ID of the entry. |
True on success or false on failed (item not found).
checkAuthentication(string $username, string $credData, string $credFormat, string $credType) : boolean|string
Authenticates the user at the backend.
For some types of authentications (notably auth:basic) the username
gets extracted from the authentication data and is then stored in
username. For security reasons the caller must ensure that this is the
username that is used for the session, overriding any username
specified in
string | $username | Username as provided in the |
string | $credData | Authentication data provided by |
string | $credFormat | Format of data as |
string | $credType | Auth type as provided by |
The user name if authentication succeeded, false otherwise.
writeSyncAnchors(string $databaseURI, string $clientAnchorNext, string $serverAnchorNext)
Stores Sync anchors after a successful synchronization to allow two-way synchronization next time.
The backend has to store the parameters in its persistence engine where user, syncDeviceID and database are the keys while client and server anchor ar the payload. See readSyncAnchors() for retrieval.
string | $databaseURI | URI of database to sync. Like calendar, tasks, contacts or notes. May include optional parameters: tasks?options=ignorecompleted. |
string | $clientAnchorNext | The client anchor as sent by the client. |
string | $serverAnchorNext | The anchor as used internally by the server. |
readSyncAnchors(string $databaseURI) : mixed
Reads the previously written sync anchors from the database.
string | $databaseURI | URI of database to sync. Like calendar, tasks, contacts or notes. May include optional parameters: tasks?options=ignorecompleted. |
Two-element array with client anchor and server anchor as stored in previous writeSyncAnchor() calls. False if no data found.
createUidMap(string $databaseURI, string $cuid, string $suid, integer $timestamp)
Creates a map entry to map between server and client IDs.
If an entry already exists, it is overwritten.
string | $databaseURI | URI of database to sync. Like calendar, tasks, contacts or notes. May include optional parameters: tasks?options=ignorecompleted. |
string | $cuid | Client ID of the entry. |
string | $suid | Server ID of the entry. |
integer | $timestamp | Optional timestamp. This can be used to 'tag' changes made in the backend during the sync process. This allows to identify these, and ensure that these changes are not replicated back to the client (and thus duplicated). See key concept "Changes and timestamps". |
eraseMap(string $databaseURI)
Erases all mapping entries for one combination of user, device ID.
This is used during SlowSync so that we really sync everything properly and no old mapping entries remain.
string | $databaseURI | URI of database to sync. Like calendar, tasks, contacts or notes. May include optional parameters: tasks?options=ignorecompleted. |
logMessage(mixed $message, integer $priority = 'INFO')
Logs a message in the backend.
TODO: This should be done via Horde_Log or the equivalent.
mixed | $message | Either a string or a PEAR_Error object. |
integer | $priority | The priority of the message. One of:
|
logFile(integer $type, string $content, boolean $wbxml = false, boolean $sessionClose = false)
Logs data to a file in the debug directory.
integer | $type | The data type. One of the Horde_SyncMlBackend::LOGFILE* constants. |
string | $content | The data content. |
boolean | $wbxml | Whether the data is wbxml encoded. |
boolean | $sessionClose | Whether this is the last SyncML message in a session. Bump the file number. |
normalize(string $databaseURI) : string
Normalizes a databaseURI to a database name, so that _normalize('tasks?ignorecompleted') should return just 'tasks'.
string | $databaseURI | URI of a database. Like calendar, tasks, contacts or notes. May include optional parameters: tasks?options=ignorecompleted. |
The normalized database name.
getParameter(string $url, string $parameter, string $default = null)
Extracts an HTTP GET like parameter from an URL.
Example: getParameter('test?q=1', 'q') == 1
string | $url | The complete URL. |
string | $parameter | The parameter name to extract. |
string | $default | A default value to return if none has been provided in the URL. |
addEntry_backend(string $user, string $databaseURI, string $content, string $contentType) : array
Adds an entry into the server database.
string | $user | The username to use. Not strictly necessery to store this, but it helps for the test environment to clean up all entries for a test user. |
string | $databaseURI | URI of Database to sync. Like calendar, tasks, contacts or notes. May include optional parameters: tasks?options=ignorecompleted. |
string | $content | The actual data. |
string | $contentType | MIME type of the content. |
PEAR_Error or suid of new entry.
replaceEntry_backend(string $user, string $databaseURI, string $content, string $contentType, string $suid) : string
Replaces an entry in the server database.
string | $user | The username to use. Not strictly necessery to store this but, it helps for the test environment to clean up all entries for a test user. |
string | $databaseURI | URI of Database to sync. Like calendar, tasks, contacts or notes. May include optional parameters: tasks?options=ignorecompleted. |
string | $content | The actual data. |
string | $contentType | MIME type of the content. |
string | $suid | Server ID of this entry. |
PEAR_Error or suid of modified entry.
deleteEntry_backend(string $user, string $databaseURI, string $suid) : boolean
Deletes an entry from the server database.
string | $user | The username to use. Not strictly necessery to store this, but it helps for the test environment to clean up all entries for a test user. |
string | $databaseURI | URI of Database to sync. Like calendar, tasks, contacts or notes. May include optional parameters: tasks?options=ignorecompleted. |
string | $suid | Server ID of the entry. |
True on success or false on failed (item not found).
_getSuid(string $databaseURI, string $cuid) : mixed
Retrieves the Server ID for a given Client ID from the map.
string | $databaseURI | URI of database to sync. Like calendar, tasks, contacts or notes. May include optional parameters: tasks?options=ignorecompleted. |
string | $cuid | The client ID. |
The server ID string or false if no entry is found.
_getCuid(string $databaseURI, string $suid) : mixed
Retrieves the Client ID for a given Server ID from the map.
string | $databaseURI | URI of database to sync. Like calendar, tasks, contacts or notes. May include optional parameters: tasks?options=ignorecompleted. |
string | $suid | The server ID. |
The client ID string or false if no entry is found.
_getChangeTS(string $databaseURI, string $suid) : mixed
Returns a timestamp stored in the map for a given Server ID.
The timestamp is the timestamp of the last change to this server ID that was done inside a sync session (as a result of a change received by the server). It's important to distinguish changes in the backend a) made by the user during normal operation and b) changes made by SyncML to reflect client updates. When the server is sending its changes it is only allowed to send type a). However the history feature in the backend my not know if a change is of type a) or type b). So the timestamp is used to differentiate between the two.
string | $databaseURI | URI of database to sync. Like calendar, tasks, contacts or notes. May include optional parameters: tasks?options=ignorecompleted. |
string | $suid | The server ID. |
The previously stored timestamp or false if no entry is found.
_trackDeletes(string $databaseURI, array $currentSuids) : array
Returns a list of item IDs that have been deleted since the last sync run and stores a complete list of IDs for next sync run.
Some backend datastores don't keep information about deleted entries. So we have to create a workaround that finds out what entries have been deleted since the last sync run. This method provides this functionality: it is called with a list of all IDs currently in the database. It then compares this list with its own previously stored list of IDs to identify those missing (and thus deleted). The passed list is then stored for the next invocation.
string | $databaseURI | URI of database to sync. Like calendar, tasks, contacts or notes. May include optional parameters: tasks?options=ignorecompleted. |
array | $currentSuids | Array of all SUIDs (primary keys) currently in the server datastore. |
Array of all entries that have been deleted since the last call.
_removeFromSuidList(string $databaseURI, array $suid)
Removes a suid from the suidlist.
Called by _trackDeletes() when updating the suidlist and deleteEntry() when removing an entry due to a client request.
string | $databaseURI | URI of database to sync. Like calendar, tasks, contacts or notes. May include optional parameters: tasks?options=ignorecompleted. |
array | $suid | The suid to remove from the list. |