Connecting to a CalDAV Server with cURL

After installing Baikal as a CalDAV/CardDAV server, I tested the connectivity to this server with cURL. I used SSL with a self-signed certificate on the web server, authentification on the CalDAV server was set to DIGEST.

This is being reflected in the cURL request by using –insecure to address the self-signed certificate and –digest for the DIGEST authentification method, when requesting the username:

curl 
--request PROPFIND
--insecure
--digest
--user USERNAME:PASSWORD
--header "Content-Type: text/xml"
--header "Brief:t"
--data "<D:propfind xmlns:D='DAV:'><D:prop><D:displayname/></D:prop></D:propfind>"
https://example.com/path/to/cal.php/principals/USERNAME

USERNAME and PASSWORD are eponymous placeholders, the object in the URL path (cal.php/principals/USERNAME) is specific for Baikal server.

The result of this query:

<?xml version="1.0" encoding="utf-8"?>
<d:multistatus 
 xmlns:d="DAV:" 
 xmlns:s="http://sabredav.org/ns" 
 xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/"
>
 <d:response>
  <d:href>/path/to/cal.php/principals/USERNAME/</d:href>
  <d:propstat>
   <d:prop>
    <d:displayname>Ron Metten</d:displayname>
   </d:prop>
   <d:status>HTTP/1.1 200 OK</d:status>
  </d:propstat>
 </d:response>
</d:multistatus>

Get current working directory in PHP with Phing

The ResolvePathTask in Phing “turns a relative path into an absolute path, with respect to specified directory or the project basedir (if no dir attribute specified)”.

We can use this to dynamically get a base path for relative path components:

<property name="URI.base" value="./"/>
<resolvepath propertyName="URI.base" file="${URI.base}"/>

With this, we compose absolute paths:

<property name="URI.utilities" value="${URI.base}/utilities"/>

Example:

<project name="sandbox" default="main">
 <target name="sandbox_init" description="Init build and set properties">
  <property name="URI.base" value="./"/>
  <resolvepath propertyName="URI.base" file="${URI.base}"/>
  <echo>Resolved [absolute] path: ${URI.base}</echo>
  <!-- Directories -->
  <property name="URI.utilities" value="${URI.base}/utilities"/>
  <echo>Utilities path: ${URI.utilities}</echo>
  <!--File names -->
  <property name="URI.autoload.outfile" value="${URI.utilities}/autoload.inc.php"/>
  <property name="URI.autoload.templatefile" value="${URI.utilities}/autoload.template.tpl"/>
 </target>
 <target name="main" depends="sandbox_init" description="Main build task"/>
</project>

The above code sample prints:
Buildfile: /var/www/sandbox/build.xml
sandbox > sandbox_init:
[echo] Resolved [absolute] path: /var/www/sandbox
[echo] Utilities path: /var/www/sandbox/utilities

Pruning the Ubuntu MRU

Imagine a situation, e.g. a kitchen review, where you don’t want your customer or colleague to see a list of you recently opened files, especially those files you opened for recreational purposes. In Ubuntu, this list is a XML file recently-used.xbel, located in the user directory under ~/.local/share.

This file consists of bookmarks:

  <bookmark href="file:///home/ron/Downloads/liferay-portal-6.1.1-ce-ga2/readme.html" added="2013-02-23T19:04:53Z" modified="2013-02-23T19:04:53Z" visited="2013-02-23T19:04:53Z">
    <info>
      <metadata owner="http://freedesktop.org">
        <mime:mime-type type="text/html"/>
        <bookmark:applications>
          <bookmark:application name="nautilus" exec="'epiphany-browser %U'" modified="2013-02-23T19:04:53Z" count="1"/>
        </bookmark:applications>
      </metadata>
    </info>
  </bookmark>

Pruning here is done by analyzing the file extension of the href attribute, let’s get rid of .flv and .mp4 entries:

<?php
/**
 * Prunes the Ubuntu MRU file.
 * 
 */
class MRUPruner
{

    /**
     * Dom object
     * @var DOMobject
     */
    private $DOM;

    /**
     * XML file name
     * @var String
     */
    private $XML;

    /**
     * Loads XML into the DOM
     *
     * @param string $XML   XML File Name
     */
    function __construct($XML) {
        $this->XML = $XML;
        $this->DOM = new DOMDocument();
        $this->DOM->load($XML);
    } // __construct()

    /**
     * Prunes MRU by applying filters
     * @uses DOM
     */
    public function prune() {

        $elements = $this->DOM->getElementsByTagName('bookmark');
        $pruned = false;

        do {
            $pruned = true;
            foreach($elements as $element) {

                $tempDocument = new DOMDocument();
                $clonedElement = $element->cloneNode(true);
                $tempDocument->appendChild($tempDocument->importNode($clonedElement, true));

                $_href = $element->getAttribute('href');
                print $_href . PHP_EOL;

                // Delete:
                $pattern = '~.*\.(flv|mp4)$~i';
                if(preg_match($pattern, $_href) == 1) {
                    print '-->delete' . PHP_EOL;
                    $element->parentNode->removeChild($element);
                    reset($elements);
                    $pruned = false;
                    break;
                } // endif

                // another pattern block here...

            } // nexteach
        } while(!$pruned);

    $this->DOM->save($this->XML);
    } // prune()

} // class

$pruner = new MRUPruner('recently-used.xbel');
$pruner->prune();

All nodes with these file extensions in the href attribute are removed from the document, the document is written back to the MRU file. The pattern block can be replaced or enhanced by another. This code does not handle the blank lines coming from deleting elements.

Remember: Use this at your own risk; Backup your data before you manipulate it.

P.S.: Being a dyed-in-the-wool data collector, I do not simply delete entries, but save them in a database for further analysis…

PhpStorm: External resource is not registered

If you happen to get an error “External resource http://example.com/example.xsd is not registered” when validating an XML file in PphStorm, check, if the URI of your noNamespaceSchemaLocation is marked red. If so, this schema is simply not loaded.

Click in the line with your schema declaration und hit <ALT><ENTER>, choose “Fetch external resource” to load this resource. The URI of your noNamespaceSchemaLocation should be marked green now and your document can be validated.