[geeklog-cvs] Geeklog-1.x/system lib-webservices.php,NONE,1.1

Dirk Haun dhaun at qs1489.pair.com
Sat Aug 11 12:48:58 EDT 2007


Update of /cvsroot/geeklog/Geeklog-1.x/system
In directory qs1489.pair.com:/tmp/cvs-serv52134/system

Added Files:
	lib-webservices.php 
Log Message:
First incarnation of the actual Webservices API, on behalf of Ramnath R Iyer (hardcoded for the static pages plugin by me)


--- NEW FILE: lib-webservices.php ---
<?php

/* Reminder: always indent with 4 spaces (no tabs). */
// +---------------------------------------------------------------------------+
// | Geeklog 1.4                                                               |
// +---------------------------------------------------------------------------+
// | lib-webservices.php                                                       |
// |                                                                           |
// | WS-related functions needed in more than one place.                       |
// +---------------------------------------------------------------------------+
// | Copyright (C) 2007 by the following authors:                              |
// |                                                                           |
// | Authors: Ramnath R Iyer        - rri AT silentyak DOT com                 |
// +---------------------------------------------------------------------------+
// |                                                                           |
// | This program is free software; you can redistribute it and/or             |
// | modify it under the terms of the GNU General Public License               |
// | as published by the Free Software Foundation; either version 2            |
// | of the License, or (at your option) any later version.                    |
// |                                                                           |
// | This program is distributed in the hope that it will be useful,           |
// | but WITHOUT ANY WARRANTY; without even the implied warranty of            |
// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             |
// | GNU General Public License for more details.                              |
// |                                                                           |
// | You should have received a copy of the GNU General Public License         |
// | along with this program; if not, write to the Free Software Foundation,   |
// | Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.           |
// |                                                                           |
// +---------------------------------------------------------------------------+
//

if (strpos ($_SERVER['PHP_SELF'], 'lib-webservices.php') !== false) {
    die ('This file can not be used on its own!');
}

// Set the default content type
header('Content-type: ' . 'application/atom+xml' . '; charset=UTF-8');

$WS_PLUGIN    = 'staticpages'; // -- dhaun 2008-08-11
$WS_INTROSPECTION = false;
$WS_TEXT = '';
$WS_ATOM_NS = 'http://www.w3.org/2005/Atom';
$WS_APP_NS  = 'http://www.w3.org/2007/app';
$WS_EXTN_NS = 'http://www.geeklog.net';

/**
 * Displays an error message with the appropriate HTTP error-code
 *
 * @param   string  $error_name     the name of the error
 * @param   string  $error_desc     a short description of the actual error (optional)
 */
function WS_error($error_code, $error_desc = '')
{
    header('Content-type: ' . 'text/html' . '; charset=UTF-8');
    switch ($error_code) {
    case PLG_RET_PRECONDITION_FAILED:
        header($_SERVER['SERVER_PROTOCOL'] . ' 412 Precondition Failed');
        break;
    case PLG_RET_PERMISSION_DENIED:
        header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden');
        break;
    case PLG_RET_AUTH_FAILED:
        header($_SERVER['SERVER_PROTOCOL'] . ' 401 Unauthorized');
        header('WWW-Authenticate: Basic realm="www.geeklog.net"');
        break;
    case PLG_RET_ERROR:
        header($_SERVER['SERVER_PROTOCOL'] . ' 400 Bad Request');
        break;
    }

    // Output exact error message here
    echo trim($error_desc);
    exit();
}

/**
 * Dissects the URI and obtains parameters
 *
 * @param   array   $args       the array to store any input parameters
 */
function WS_dissectURI(&$args)
{
    global $WS_PLUGIN, $WS_INTROSPECTION;

    $WS_PLUGIN = 'staticpages'; // -- dhaun 2008-08-11
    $args = array();

    $uri_parts = explode('&', $_SERVER['QUERY_STRING']);
    foreach ($uri_parts as $param) {
        $uri_parts = explode('=', $param);
        $param_key = COM_applyFilter($uri_parts[0]);
        $param_val = COM_applyFilter($uri_parts[1]);

        switch ($param_key) {
        case 'introspection':
                $WS_INTROSPECTION = true;
        case 'plugin':
            /*if (!empty($param_val)) {
                $WS_PLUGIN = $param_val;
            }*/
            break;
        default:
            if (!empty($param_val)) {
                $args[$param_key] = $param_val;
            }
            break;
        }
    }
}

/**
 * Handles the POST request
 */
function WS_post()
{
    global $WS_PLUGIN, $WS_ATOM_NS, $WS_APP_NS, $WS_EXTN_NS, $_CONF;

    WS_dissectURI($args);

    $args['category'] = array();

    WS_xmlToArgs($args);

    /* The default action is submit */
    if (empty($args['action'])) {
        $action = 'submit';
    }

    // @TODO Store array $args
    // object id has already been stored from the URI

    /* Indicates that the method are being called by the webservice */
    $args['gl_svc'] = true;

    // Call PLG_invokeService here
    $ret = PLG_invokeService($WS_PLUGIN, $action, $args, $out, $svc_msg);

    if ($ret == PLG_RET_OK) {
        header($_SERVER['SERVER_PROTOCOL'] . ' 201 Created');
        header('Location: ' . 'http://' . $_SERVER['HTTP_HOST'] . '/webservices/atom/?plugin=' . $WS_PLUGIN . '&id' . '=' . $svc_msg['id']);
        // Output the actual object here
        return;
    }

    WS_error($ret, $svc_msg['error_desc']);
}

/**
 * Handles the PUT request
 */
function WS_put()
{
    global $WS_PLUGIN, $WS_ATOM_NS, $WS_APP_NS, $WS_EXTN_NS, $_CONF;

    WS_dissectURI($args);

    WS_xmlToArgs($args);

    // @TODO Store array $args
    // object id has already been stored from the URI
    /* Indicates that the method are being called by the webservice */
    $args['gl_svc']  = true;
    $args['gl_edit'] = true;
    $args['gl_etag'] = trim($_SERVER['HTTP_IF_MATCH'], '"');

    // Call PLG_invokeService here
    $ret = PLG_invokeService($WS_PLUGIN, 'submit', $args, $out, $svc_msg);

    if ($ret == PLG_RET_OK) {
        header($_SERVER['SERVER_PROTOCOL'] . ' 200 OK');
        return;
    }

    WS_error($ret, $svc_msg['error_desc']);

}

/**
 * Handles the GET request
 */
function WS_get()
{
    global $WS_PLUGIN, $WS_INTROSPECTION, $WS_ATOM_NS, $WS_APP_NS, $WS_EXTN_NS, $_CONF;

    WS_dissectURI($args);

    if ($WS_INTROSPECTION) {

        header('Content-type: ' . 'application/atomserv+xml' . '; charset=UTF-8');

        $atom_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/webservices/atom/';

        /* 'story' is the default plugin */
        if (empty($WS_PLUGIN)) {
            $WS_PLUGIN = 'staticpages'; // for now --dhaun 2008-08-11
        }

        $atom_uri .= '?plugin=' . $WS_PLUGIN;

        /* It might be simpler to do this part directly :-/ */

        $atom_doc = new DOMDocument('1.0', 'utf-8');
        $root_elem = $atom_doc->createElementNS($WS_APP_NS, 'app:service');
        $atom_doc->appendChild($root_elem);
        $atom_doc->createAttributeNS($WS_ATOM_NS, 'atom:service');
        $atom_doc->createAttributeNS($WS_EXTN_NS, 'gl:service');

        $workspace = $atom_doc->createElement('app:workspace');
        $root_elem->appendChild($workspace);

        $title = $atom_doc->createElement('atom:title', $_CONF['site_name']);
        $workspace->appendChild($title);

        $collection = $atom_doc->createElement('app:collection');
        $collection->setAttribute('href', $atom_uri);
        $workspace->appendChild($collection);

        $title = $atom_doc->createElement('atom:title', 'Entries');
        $collection->appendChild($title);

        $entry = $atom_doc->createElement('app:accept', 'entry');
        $collection->appendChild($entry);

        $categories = $atom_doc->createElement('app:categories');
        $categories->setAttribute('fixed', 'yes');
        $collection->appendChild($categories);

        $topics = array();
        $msg = array();
        $ret = PLG_invokeService($WS_PLUGIN, 'getTopicList', null, $topics, $msg);
        if ($ret == PLG_RET_OK) {
            foreach ($topics as $t) {
                $topic = $atom_doc->createElement('atom:category');
                $topic->setAttribute('term', htmlentities($t));
                $categories->appendChild($topic);
            }
        }

        WS_write($atom_doc->saveXML());

        return;
    }

    // @TODO Store array $args
    // object id has already been stored from the URI
    /* Indicates that the method is being called by the webservice */
    $args['gl_svc'] = true;

    $ret = PLG_invokeService($WS_PLUGIN, 'get', $args, $out, $svc_msg);

    if ($ret == PLG_RET_OK) {
            header($_SERVER['SERVER_PROTOCOL'] . ' 200 OK');
            header('Content-type: application/atom+xml; charset=UTF-8');
            // Output the actual object/objects here

            if (!$svc_msg['gl_feed']) {
                /* This is an entry, not a feed */
                $etag = trim($_SERVER['HTTP_IF_NONE_MATCH'], '"');
                if (!empty($etag) && ($out['updated'] == $etag)) {
                    header($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified');
                    exit();
                } else {
                    header('Etag: "' . $out['updated'] . '"');
                }
                $atom_doc = new DOMDocument('1.0', 'utf-8');

                $entry_elem = $atom_doc->createElementNS($WS_ATOM_NS, 'atom:entry');
                $atom_doc->appendChild($entry_elem);
                $atom_doc->createAttributeNS($WS_APP_NS, 'app:entry');
                $atom_doc->createAttributeNS($WS_EXTN_NS, 'gl:entry');

                WS_arrayToEntryXML($out, $svc_msg['output_fields'], $entry_elem, $atom_doc);
                WS_write($atom_doc->saveXML());
            } else {
                /* Output the feed here */
                $atom_doc = new DOMDocument('1.0', 'utf-8');

                $feed_elem = $atom_doc->createElementNS($WS_ATOM_NS, 'atom:feed');
                $atom_doc->appendChild($feed_elem);
                $atom_doc->createAttributeNS($WS_APP_NS, 'app:feed');
                $atom_doc->createAttributeNS($WS_EXTN_NS, 'gl:feed');

                $feed_id = $atom_doc->createElement('atom:id', $_CONF['site_name']);
                $feed_elem->appendChild($feed_id);

                $feed_title = $atom_doc->createElement('atom:title', $_CONF['site_name']);
                $feed_elem->appendChild($feed_title);

                $feed_updated = $atom_doc->createElement('atom:updated', date('c'));
                $feed_elem->appendChild($feed_updated);

                $feed_link = $atom_doc->createElement('atom:link');
                $feed_link->setAttribute('rel', 'self');
                $feed_link->setAttribute('type', 'application/atom+xml');
                $feed_link->setAttribute('href', 'http://' . $_SERVER['HTTP_HOST'] . '/webservices/atom/?plugin=' . htmlentities($WS_PLUGIN));
                $feed_elem->appendChild($feed_link);

                if (!empty($svc_msg['offset'])) {
                    $next_link = $atom_doc->createElement('atom:link');
                    $next_link->setAttribute('rel', 'next');
                    $next_link->setAttribute('type', 'application/atom+xml');
                    $next_link->setAttribute('href', 'http://' . $_SERVER['HTTP_HOST'] . '/webservices/atom/?plugin=' . htmlentities($WS_PLUGIN) . '&offset=' . $svc_msg['offset']);
                    $feed_elem->appendChild($next_link);
                }

                foreach ($out as $entry_array) {
                    $entry_elem = $atom_doc->createElement('atom:entry');
                    WS_arrayToEntryXML($entry_array, $svc_msg['output_fields'], $entry_elem, $atom_doc);
                    $feed_elem->appendChild($entry_elem);
                }

                WS_write($atom_doc->saveXML());
            }

            return;
    }

    WS_error($ret, $svc_msg['error_desc']);
}

/**
 * Handles the DELETE request
 */
function WS_delete()
{
    global $WS_PLUGIN, $WS_ATOM_NS, $WS_APP_NS, $WS_EXTN_NS, $_CONF;

    WS_dissectURI($args);

    // @TODO Store array $args
    // object id has already been stored from the URI

    /* Indicates that the method are being called by the webservice */
    $args['gl_svc'] = true;

    $ret = PLG_invokeService($WS_PLUGIN, 'delete', $args, $out, $svc_msg);

    if ($ret == PLG_RET_OK) {
            header($_SERVER['SERVER_PROTOCOL'] . ' 200 OK');
            return;
    }

    WS_error($ret, $svc_msg['error_desc']);

}

/**
 * Converts the input XML into an argument array
 *
 * @param   array      &$args       the array to which the arguments are to be appended
 */
function WS_xmlToArgs(&$args)
{
    global $_USER, $WS_EXTN_NS, $WS_ATOM_NS, $WS_APP_NS;

    /* Previous data in args is NOT deleted */

    @$atom_doc = new DOMDocument();
    if (!@$atom_doc->load('php://input')) {
        WS_error(PLG_RET_ERROR, 'Invalid XML document');
    }

    /* Get the entry */
    $entry_element = $atom_doc->getElementsByTagName('entry')->item(0);
    if ($entry_element == null) {
        WS_error(PLG_RET_ERROR, 'Invalid Atom entry');
    }

    /* Get the action, if it exists */
    $action_element = $entry_element->getElementsByTagNameNS($WS_EXTN_NS, 'action')->item(0);
    $action = '';
    if ($action_element != null) {
        $args['action'] = strtolower((string)($action_element->firstChild->data));
    }

    if ($entry_element->hasChildNodes()) {
        $nodes = $entry_element->childNodes;
        $args['category'] = array();
        for ($index = 0; $index < $nodes->length; $index++) {
            $node = $nodes->item($index);

            if (($node->namespaceURI != $WS_ATOM_NS) && ($node->namespaceURI != $WS_EXTN_NS)) {
                continue;
            }

            switch ($node->localName) {
            case 'author':
                $author_name_element = $node->getElementsByTagName('name')->item(0);
                if ($author_name_element != null) {
                    $args['author_name'] = (string)($author_name_element->firstChild->nodeValue);
                }
                $author_uid_element = $node->getElementsByTagNameNS($WS_EXTN_NS, 'uid')->item(0);
                if ($author_uid_element != null) {
                    $args['uid'] = (string)($author_uid_element->firstChild->nodeValue);
                }
                break;
            case 'category':
                $args['category'][] = (string)$node->getAttribute('term');
                break;
            case 'updated':
                $args['updated'] = (string)$node->firstChild->nodeValue;
                break;
            default:
                if ($node->nodeType == XML_ELEMENT_NODE) {
                    $is_array = 1;
                    $child_nodes = $node->childNodes;
                    if ($child_nodes == null)
                        continue;

                    $args[$node->localName] = array();
                    for ($i = 0; $i < $child_nodes->length; $i++) {
                        $child_node = $child_nodes->item($i);
                        if ($child_node->nodeType == XML_TEXT_NODE) {
                            $args[$node->localName] = $child_node->nodeValue;
                            continue;
                        } elseif ($child_node->nodeType == XML_ELEMENT_NODE) {
                            if ($child_node->firstChild->nodeType == XML_TEXT_NODE) {
                                $args[$node->localName][] = $child_node->firstChild->nodeValue;
                            }
                        }
                    }
                }
            }
        }

	if (empty($args['updated'])) {
		$args['updated'] = date('c');
	}
	$args['publish_month'] = date('m', strtotime($args['updated']));
	$args['publish_year'] = date('Y', strtotime($args['updated']));
	$args['publish_day'] = date('d', strtotime($args['updated']));
	$args['publish_hour'] = date('H', strtotime($args['updated']));
	$args['publish_minute'] = date('i', strtotime($args['updated']));
	$args['publish_second'] = date('s', strtotime($args['updated']));

        if (empty($args['uid'])) {
            $args['uid'] = $_USER['uid'];
        }
    }
}

/**
 * Converts an array into an XML entry node
 *
 * @param   DOMDocument &$atom_doc  the Atom document to which the entry should be appended
 * @param   array       $arr        the array which is to be converted into XML
 */
function WS_arrayToEntryXML($arr, $extn_elements, &$entry_elem, &$atom_doc)
{
    global $WS_PLUGIN, $WS_ATOM_NS, $WS_APP_NS, $WS_EXTN_NS, $_CONF;

    /* Standard Atom elements */

    $id = $atom_doc->createElement('atom:id', $arr['id']);
    $entry_elem->appendChild($id);

    $updated = $atom_doc->createElement('atom:updated', $arr['updated']);
    $entry_elem->appendChild($updated);

    $title = $atom_doc->createElement('atom:title', $arr['title']);
    $title->setAttribute('type', 'text');
    $entry_elem->appendChild($title);

    foreach ($arr['category'] as $topic) {
        $category = $atom_doc->createElement('atom:category');
        $category->setAttribute('term', $topic);
        $entry_elem->appendChild($category);
    }

    if (!empty($arr['summary'])) {
        $summary = $atom_doc->createElement('atom:summary', $arr['summary']);
        $summary->setAttribute('type', $arr['content_type']);
        $entry_elem->appendChild($summary);
    }

    if (!empty($arr['id'])) {
        $link_self = $atom_doc->createElement('atom:link');
        $link_self->setAttribute('rel', 'edit');
        $link_self->setAttribute('type', 'application/atom+xml');
        $link_self->setAttribute('href', 'http://' . $_SERVER['HTTP_HOST'] . '/webservices/atom/?plugin=' . htmlentities($WS_PLUGIN) . '&id=' . htmlentities($arr['id']));
        $entry_elem->appendChild($link_self);
    }

    $content = $atom_doc->createElement('atom:content', $arr['content']);
    $content->setAttribute('type', $arr['content_type']);
    $entry_elem->appendChild($content);

    $author = $atom_doc->createElement('atom:author');
    $author_name = $atom_doc->createElement('atom:name', $arr['author_name']);
    $author->appendChild($author_name);
    $entry_elem->appendChild($author);

    /* Geeklog-specific elements */

    foreach ($extn_elements as $elem) {
        if (is_array($arr[$elem])) {
            $count = 0;
            $extn_elem = $atom_doc->createElement('gl:' . $elem);
            foreach ($arr[$elem] as $param) {
                if (empty($param)) {
                    continue;
                }

                $count += 1;

                $param_elem = $atom_doc->createElement('gl:param', $param);
                $extn_elem->appendChild($param_elem);
            }
            if ($count > 0) {
                $entry_elem->appendChild($extn_elem);
            }
        } else {
            $extn_elem = $atom_doc->createElement('gl:' . $elem, $arr[$elem]);
            if (!empty($arr[$elem])) {
                $entry_elem->appendChild($extn_elem);
            }
        }
    }

    return $entry_elem;
}

/**
 * Authenticates the user if authentication headers are present
 */
function WS_authenticate()
{
    global $_USER;

    $uid = '';

    if (isset($_SERVER['PHP_AUTH_USER'])) {
        $username = $_SERVER['PHP_AUTH_USER'];
        $password = $_SERVER['PHP_AUTH_PW'];

        $status = SEC_authenticate($username, $password, $uid);
    } elseif (!empty($_REQUEST['gl_auth_header'])) {
        /* PHP installed as CGI may not have access to authorization headers of Apache
         * In that case, use .htaccess to store the auth header as a request variable
         * called gl_auth_digest
         */

        list($auth_type, $auth_data) = explode(' ', $_REQUEST['gl_auth_digest']);
        list($username, $password) = explode(':', base64_decode($auth_data));

        $status = SEC_authenticate($username, $password, $uid);
    } else {
        return;
    }

    if ($status == -1) {
        WS_error(PLG_RET_AUTH_FAILED);
    } elseif ($status == 3) {
        $_USER = SESS_getUserDataFromId ($uid);
        PLG_loginUser ($_USER['uid']);
    }

    /**
    * Global array of groups current user belongs to
    */

    if (!COM_isAnonUser()) {
        $_GROUPS = SEC_getUserGroups($_USER['uid']);
    } else {
        $_GROUPS = SEC_getUserGroups(1);
    }

    /**
    * Global array of current user permissions [read,edit]
    */

    $_RIGHTS = explode( ',', SEC_getUserPermissions() );
}

/**
 * Buffers text for output
 *
 * @param   string      $text       the text to be written
 */
function WS_write($text)
{
    global $WS_TEXT;

    $WS_TEXT .= $text;

}

/**
 * Writes buffered text to output
 */
function WS_writeSync()
{
    global $WS_TEXT;

    echo $WS_TEXT;

}

?>




More information about the geeklog-cvs mailing list