D41d8cd98f00b204e9800998ecf8427e

I have no experience building Web Services at all. I build this template in hope that this is right point to start from. Am I right? (Any refactoring and/or comments are welcome.)

<?php

# Template for Web Service

# http://path/to/webservice.php?foo=bar&outputformat=json&sign=xxxx

# Based on
# http://php.net/manual/en/function.is-array.php#102652
function is_assoc($array)
{
	if (!is_array($array))
		return false;

	$expectedkey = 0;
	foreach ($array as $key => $value) {
		if ($key != $expectedkey)
			return true;
		++$expectedkey;
	}

	return false;
}

# This solution is based on
# http://php.net/manual/en/book.simplexml.php#101949
# http://php.net/manual/en/book.wddx.php
function xmlencode($var)
{
	$xml = new SimpleXMLElement('<xmlencode/>');

	$append = function ($append, $node, $item) {
		if (is_array($item)) {
			if (is_assoc($item)) {
				$struct = $node->addChild('struct');
				foreach ($item as $itemkey => $itemvalue) {
					$var = $struct->addChild('var');
					$var->addAttribute('name', $itemkey);
					$append($append, $struct, $itemvalue);
				}
			}
			else {
				$array = $node->addChild('array');
				$array->addAttribute('length', count($item));
				foreach ($item as $itemvalue) {
					$append($append, $array, $itemvalue);
				}
			}
		}
		else {
			$node->addChild(gettype($item), $item);
		}
	};

	$append($append, $xml, $var);
	return $xml->saveXml();
}

function verifyrequest()
{
	$secretkey = '9377d31db4dd92834e2219d88073f5af';

	$query = preg_replace('/sign=[[:xdigit:]]{32}/', '',
		"{$_SERVER['QUERY_STRING']}{$secretkey}");
	if (!isset($_GET['sign']) || $_GET['sign'] != md5($query)) {
		header('HTTP/1.1 403 Forbidden');
		exit('Access denied');
		return false;
	}

	$GLOBALS['outputformat'] = 'json';
	if (isset($_GET['outputformat'])) {
		$GLOBALS['outputformat'] = $_GET['outputformat'];
	}

	return true;
}

function outputresult($result)
{
	switch ($GLOBALS['outputformat']) {
	case 'json':
		# http://stackoverflow.com/questions/477816/the-right-json-content-type#2590013
		header('Content-Type: application/json');
		exit(json_encode($result));

	case 'wddx':
		header('Content-Type: text/xml; charset=utf-8');
		exit(wddx_serialize_value($result));

	case 'xml':
		header('Content-Type: text/xml; charset=utf-8');
		exit(xmlencode($result));

	case 'serialize':
		header('Content-Type: text/plain; charset=utf-8');
		exit(serialize($result));

	default:
		header('HTTP/1.1 400 Bad Request');
		exit('Invalid Output Format');
	}
}

function processrequest()
{
	return array(1, 2, 3 => array('a', 'b', 'c'));
}

if (verifyrequest()) {
	outputresult(processrequest());
}

?>

Refactorings

No refactoring yet !

D41d8cd98f00b204e9800998ecf8427e

Vladimir Barbarosh

April 14, 2011, April 14, 2011 12:16, permalink

No rating. Login to rate!

I changed the way query string are signed and add example of using service from command line.

<?php

# Template for Web Service

# http://path/to/webservice.php?foo=bar&outputformat=json&sign=xxxx

# bash(1)
#	secretkey=00000000000000000000000000000000
#	query="foo=bar&outputformat=json"
#	sign=$(echo -n "${query}:${secretkey}" | md5sum | cut -d' ' -f1)
#	curl --silent --show-error --fail \
#		"http://path/to/webservice.php?${query}&sign=${sign}"

# Based on
# http://php.net/manual/en/function.is-array.php#102652
function is_assoc($array)
{
	if (!is_array($array))
		return false;

	$expectedkey = 0;
	foreach ($array as $key => $value) {
		if ($key != $expectedkey)
			return true;
		++$expectedkey;
	}

	return false;
}

# Based on
# http://php.net/manual/en/book.simplexml.php#101949
# http://php.net/manual/en/book.wddx.php
function xmlencode($var)
{
	$xml = new SimpleXMLElement('<xmlencode/>');

	$append = function ($append, $node, $item) {
		if (is_array($item)) {
			if (is_assoc($item)) {
				$struct = $node->addChild('struct');
				foreach ($item as $itemkey => $itemvalue) {
					$var = $struct->addChild('var');
					$var->addAttribute('name', $itemkey);
					$append($append, $struct, $itemvalue);
				}
			}
			else {
				$array = $node->addChild('array');
				$array->addAttribute('length', count($item));
				foreach ($item as $itemvalue) {
					$append($append, $array, $itemvalue);
				}
			}
		}
		else {
			$node->addChild(gettype($item), $item);
		}
	};

	$append($append, $xml, $var);
	return $xml->saveXml();
}

function verifyrequest()
{
	$secretkey = '00000000000000000000000000000000';

	$query = preg_replace('/\&?sign=[[:xdigit:]]{32}/', '',
		"{$_SERVER['QUERY_STRING']}:{$secretkey}");
	if (!isset($_GET['sign']) || $_GET['sign'] != md5($query)) {
		header('HTTP/1.1 403 Forbidden');
		exit('Access denied');
		return false;
	}

	$GLOBALS['outputformat'] = 'json';
	if (isset($_GET['outputformat'])) {
		$GLOBALS['outputformat'] = $_GET['outputformat'];
	}

	return true;
}

function outputresult($result)
{
	switch ($GLOBALS['outputformat']) {
	case 'json':
		# http://stackoverflow.com/questions/477816/the-right-json-content-type#2590013
		header('Content-Type: application/json');
		exit(json_encode($result));

	case 'wddx':
		header('Content-Type: text/xml; charset=utf-8');
		exit(wddx_serialize_value($result));

	case 'xml':
		header('Content-Type: text/xml; charset=utf-8');
		exit(xmlencode($result));

	case 'serialize':
		header('Content-Type: text/plain; charset=utf-8');
		exit(serialize($result));

	default:
		header('HTTP/1.1 400 Bad Request');
		exit('Invalid Output Format');
	}
}

function processrequest()
{
	return array(1, 2, 3 => array('a', 'b', 'c'));
}

if (verifyrequest()) {
	outputresult(processrequest());
}

?>

Your refactoring





Format Copy from initial code

or Cancel