FEATURE: First commit for ProcessMaker Rest Support

What is Functional

- Restler thirdparty library added
- Restler integration with gulliver added
- Rest requests are dispatched by sysGeneric
- Restler autodiscover for classes that implements Restler iAuthenticate interface added

What Missing

- ProcessMaker Api implemented yet
- some rest api class are in workflow/engine/services/rest/*.php
This commit is contained in:
Erik Amaru Ortiz
2012-08-10 16:54:12 -04:00
parent f783bc09f4
commit 9b1867a410
41 changed files with 8285 additions and 85 deletions

View File

@@ -917,7 +917,7 @@ class G
* @param string $urlLink
* @return string
*/
static function parseURI($uri, $config = array())
static function parseURI($uri, $isRestRequest = false)
{
//*** process the $_POST with magic_quotes enabled
// The magic_quotes_gpc feature has been DEPRECATED as of PHP 5.3.0.
@@ -926,82 +926,111 @@ class G
}
$aRequestUri = explode('/', $uri );
if ($isRestRequest) {
$args = self::parseRestUri($aRequestUri);
} else {
$args = self::parseNormalUri($aRequestUri);
}
define("SYS_LANG", $args['SYS_LANG']);
define("SYS_SKIN", $args['SYS_SKIN']);
define('SYS_COLLECTION', $args['SYS_COLLECTION']);
define('SYS_TARGET', $args['SYS_TARGET']);
if ( $args['SYS_COLLECTION'] == 'js2' ) {
print "ERROR"; die;
}
}
public function parseNormalUri($aRequestUri)
{
if (substr($aRequestUri[1], 0, 3) == 'sys') {
define('SYS_TEMP', substr($aRequestUri[1], 3));
}
else {
} else {
define("ENABLE_ENCRYPT", 'yes');
define('SYS_TEMP', $aRequestUri[1]);
$plain = '/sys' . SYS_TEMP;
for ($i = 2; $i < count($aRequestUri); $i++) {
$decoded = G::decrypt(urldecode($aRequestUri[$i]), URL_KEY);
if ( $decoded == 'sWì' ) $decoded = $VARS[$i]; //this is for the string "../"
if ( $decoded == 'sWì' ) {
$decoded = $VARS[$i]; //this is for the string "../"
}
$plain .= '/' . $decoded;
}
$_SERVER["REQUEST_URI"] = $plain;
}
$CURRENT_PAGE = $_SERVER["REQUEST_URI"];
$work = explode('?', $_SERVER["REQUEST_URI"]);
$work = explode('?', $CURRENT_PAGE);
if ( count($work) > 1 )
if (count($work) > 1) {
define('SYS_CURRENT_PARMS', $work[1]);
else
} else {
define('SYS_CURRENT_PARMS', '');
}
define('SYS_CURRENT_URI', $work[0]);
if (!defined('SYS_CURRENT_PARMS'))
if (!defined('SYS_CURRENT_PARMS')) {
define('SYS_CURRENT_PARMS', $work[1]);
}
$preArray = explode('&', SYS_CURRENT_PARMS);
$buffer = explode('.', $work[0]);
if ( count($buffer) == 1 ) $buffer[1]='';
if (count($buffer) == 1) {
$buffer[1]='';
}
//request type
define('REQUEST_TYPE', ($buffer[1] != "" ?$buffer[1] : 'html'));
$toparse = substr($buffer[0], 1, strlen($buffer[0]) - 1);
$URL = "";
$URI_VARS = explode('/', $toparse);
for ( $i=3; $i < count( $URI_VARS) ; $i++)
$URL .= $URI_VARS[$i].'/';
$URI_VARS = explode('/', $toparse);
$uriVars = explode('/', $toparse);
unset($work);
unset($buffer);
unset($toparse);
array_shift($uriVars);
array_shift($URI_VARS);
$SYS_LANG = array_shift($URI_VARS);
$SYS_SKIN = array_shift($URI_VARS);
$SYS_COLLECTION = array_shift($URI_VARS);
$SYS_TARGET = array_shift($URI_VARS);
$args = array();
$args['SYS_LANG'] = array_shift($uriVars);
$args['SYS_SKIN'] = array_shift($uriVars);
$args['SYS_COLLECTION'] = array_shift($uriVars);
$args['SYS_TARGET'] = array_shift($uriVars);
//to enable more than 2 directories...in the methods structure
$exit = 0;
while ( count ( $URI_VARS ) > 0 && $exit == 0) {
$SYS_TARGET .= '/' . array_shift($URI_VARS);
while (count($uriVars) > 0) {
$args['SYS_TARGET'] .= '/' . array_shift($uriVars);
}
/* Fix to prevent use uxs skin outside siplified interface,
because that skin is not compatible with others interfaces*/
if ($SYS_SKIN == 'uxs' && $SYS_COLLECTION != 'home' && $SYS_COLLECTION != 'cases') {
if ($args['SYS_SKIN'] == 'uxs' && $args['SYS_COLLECTION'] != 'home' && $args['SYS_COLLECTION'] != 'cases') {
$config = System::getSystemConfiguration();
$SYS_SKIN = $config['default_skin'];
$args['SYS_SKIN'] = $config['default_skin'];
}
define("SYS_LANG", $SYS_LANG);
define("SYS_SKIN", $SYS_SKIN);
define('SYS_COLLECTION', $SYS_COLLECTION);
define('SYS_TARGET', $SYS_TARGET);
if ( $SYS_COLLECTION == 'js2' ) {
print "ERROR"; die;
return $args;
}
public function parseRestUri($requestUri)
{
$args = array();
//$args['SYS_TEMP'] = $requestUri[1];
define('SYS_TEMP', $requestUri[2]);
$restUri = '';
for ($i=3; $i < count($requestUri); $i++) {
$restUri .= '/' . $requestUri[$i];
}
$args['SYS_LANG'] = 'en'; // TODO, this can be set from http header
$args['SYS_SKIN'] = '';
$args['SYS_COLLECTION'] = '';
$args['SYS_TARGET'] = $restUri;
return $args;
}
function strip_slashes($vVar) {
@@ -5134,7 +5163,43 @@ function getDirectorySize($path,$maxmtime=0)
return false;
}
}
};
/**
* This method allow dispatch rest services using 'Restler' thirdparty library
*
* @author Erik Amaru Ortiz <aortiz.erik@gmail.com>
*/
public function dispatchRestService($uri)
{
require_once 'restler/restler.php';
$rest = new Restler();
$rest->setSupportedFormats('JsonFormat', 'XmlFormat');
// override global REQUEST_URI to pass to Restler library
$_SERVER['REQUEST_URI'] = $uri;
// getting all services class
$srvClasses = glob(PATH_SERVICES_REST . '*.php');
foreach ($srvClasses as $classFile) {
require_once $classFile;
$className = str_replace('.php', '', basename($classFile));
$reflClass = new ReflectionClass($className);
// verify if there is an auth class implementing 'iAuthenticate'
if ($reflClass->implementsInterface('iAuthenticate')) {
// auth class found, set as restler authentication class handler
$rest->addAuthenticationClass($className);
} else {
// add api class
$rest->addAPIClass($className);
}
}
$rest->handle();
}
}
/**
* eprint

View File

@@ -0,0 +1,87 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Amf
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Constants.php 20096 2010-01-06 02:05:09Z bkarwin $
*/
/**
* The following constants are used throughout serialization and
* deserialization to detect the AMF marker and encoding types.
*
* @package Zend_Amf
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
final class Zend_Amf_Constants
{
const AMF0_NUMBER = 0x00;
const AMF0_BOOLEAN = 0x01;
const AMF0_STRING = 0x02;
const AMF0_OBJECT = 0x03;
const AMF0_MOVIECLIP = 0x04;
const AMF0_NULL = 0x05;
const AMF0_UNDEFINED = 0x06;
const AMF0_REFERENCE = 0x07;
const AMF0_MIXEDARRAY = 0x08;
const AMF0_OBJECTTERM = 0x09;
const AMF0_ARRAY = 0x0a;
const AMF0_DATE = 0x0b;
const AMF0_LONGSTRING = 0x0c;
const AMF0_UNSUPPORTED = 0x0e;
const AMF0_XML = 0x0f;
const AMF0_TYPEDOBJECT = 0x10;
const AMF0_AMF3 = 0x11;
const AMF0_OBJECT_ENCODING = 0x00;
const AMF3_UNDEFINED = 0x00;
const AMF3_NULL = 0x01;
const AMF3_BOOLEAN_FALSE = 0x02;
const AMF3_BOOLEAN_TRUE = 0x03;
const AMF3_INTEGER = 0x04;
const AMF3_NUMBER = 0x05;
const AMF3_STRING = 0x06;
const AMF3_XML = 0x07;
const AMF3_DATE = 0x08;
const AMF3_ARRAY = 0x09;
const AMF3_OBJECT = 0x0A;
const AMF3_XMLSTRING = 0x0B;
const AMF3_BYTEARRAY = 0x0C;
const AMF3_OBJECT_ENCODING = 0x03;
// Object encodings for AMF3 object types
const ET_PROPLIST = 0x00;
const ET_EXTERNAL = 0x01;
const ET_DYNAMIC = 0x02;
const ET_PROXY = 0x03;
const FMS_OBJECT_ENCODING = 0x01;
/**
* Special content length value that indicates "unknown" content length
* per AMF Specification
*/
const UNKNOWN_CONTENT_LENGTH = -1;
const URL_APPEND_HEADER = 'AppendToGatewayUrl';
const RESULT_METHOD = '/onResult';
const STATUS_METHOD = '/onStatus';
const CREDENTIALS_HEADER = 'Credentials';
const PERSISTENT_HEADER = 'RequestPersistentHeader';
const DESCRIBE_HEADER = 'DescribeService';
const GUEST_ROLE = 'anonymous';
}

View File

@@ -0,0 +1,424 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Amf
* @subpackage Parse_Amf3
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Deserializer.php 21210 2010-02-27 10:37:39Z yoshida@zend.co.jp $
*/
/** Zend_Amf_Constants */
require_once 'Zend/Amf/Constants.php';
/** Zend_Amf_Parse_Deserializer */
require_once 'Zend/Amf/Parse/Deserializer.php';
/** Zend_Amf_Parse_TypeLoader */
require_once 'Zend/Amf/Parse/TypeLoader.php';
/**
* Read an AMF3 input stream and convert it into PHP data types.
*
* @todo readObject to handle Typed Objects
* @todo readXMLStrimg to be implemented.
* @todo Class could be implemented as Factory Class with each data type it's own class.
* @package Zend_Amf
* @subpackage Parse_Amf3
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Amf_Parse_Amf3_Deserializer extends Zend_Amf_Parse_Deserializer
{
/**
* Total number of objects in the referenceObject array
* @var int
*/
protected $_objectCount;
/**
* An array of reference objects per amf body
* @var array
*/
protected $_referenceObjects = array();
/**
* An array of reference strings per amf body
* @var array
*/
protected $_referenceStrings = array();
/**
* An array of reference class definitions per body
* @var array
*/
protected $_referenceDefinitions = array();
/**
* Read AMF markers and dispatch for deserialization
*
* Checks for AMF marker types and calls the appropriate methods
* for deserializing those marker types. markers are the data type of
* the following value.
*
* @param integer $typeMarker
* @return mixed Whatever the corresponding PHP data type is
* @throws Zend_Amf_Exception for unidentified marker type
*/
public function readTypeMarker($typeMarker = null)
{
if(null === $typeMarker) {
$typeMarker = $this->_stream->readByte();
}
switch($typeMarker) {
case Zend_Amf_Constants::AMF3_UNDEFINED:
return null;
case Zend_Amf_Constants::AMF3_NULL:
return null;
case Zend_Amf_Constants::AMF3_BOOLEAN_FALSE:
return false;
case Zend_Amf_Constants::AMF3_BOOLEAN_TRUE:
return true;
case Zend_Amf_Constants::AMF3_INTEGER:
return $this->readInteger();
case Zend_Amf_Constants::AMF3_NUMBER:
return $this->_stream->readDouble();
case Zend_Amf_Constants::AMF3_STRING:
return $this->readString();
case Zend_Amf_Constants::AMF3_DATE:
return $this->readDate();
case Zend_Amf_Constants::AMF3_ARRAY:
return $this->readArray();
case Zend_Amf_Constants::AMF3_OBJECT:
return $this->readObject();
case Zend_Amf_Constants::AMF3_XML:
case Zend_Amf_Constants::AMF3_XMLSTRING:
return $this->readXmlString();
case Zend_Amf_Constants::AMF3_BYTEARRAY:
return $this->readString();
default:
require_once 'Zend/Amf/Exception.php';
throw new Zend_Amf_Exception('Unsupported type marker: ' . $typeMarker);
}
}
/**
* Read and deserialize an integer
*
* AMF 3 represents smaller integers with fewer bytes using the most
* significant bit of each byte. The worst case uses 32-bits
* to represent a 29-bit number, which is what we would have
* done with no compression.
* - 0x00000000 - 0x0000007F : 0xxxxxxx
* - 0x00000080 - 0x00003FFF : 1xxxxxxx 0xxxxxxx
* - 0x00004000 - 0x001FFFFF : 1xxxxxxx 1xxxxxxx 0xxxxxxx
* - 0x00200000 - 0x3FFFFFFF : 1xxxxxxx 1xxxxxxx 1xxxxxxx xxxxxxxx
* - 0x40000000 - 0xFFFFFFFF : throw range exception
*
* 0x04 -> integer type code, followed by up to 4 bytes of data.
*
* Parsing integers on OSFlash for the AMF3 integer data format:
* @link http://osflash.org/amf3/parsing_integers
* @return int|float
*/
public function readInteger()
{
$count = 1;
$intReference = $this->_stream->readByte();
$result = 0;
while ((($intReference & 0x80) != 0) && $count < 4) {
$result <<= 7;
$result |= ($intReference & 0x7f);
$intReference = $this->_stream->readByte();
$count++;
}
if ($count < 4) {
$result <<= 7;
$result |= $intReference;
} else {
// Use all 8 bits from the 4th byte
$result <<= 8;
$result |= $intReference;
// Check if the integer should be negative
if (($result & 0x10000000) != 0) {
//and extend the sign bit
$result |= ~0xFFFFFFF;
}
}
return $result;
}
/**
* Read and deserialize a string
*
* Strings can be sent as a reference to a previously
* occurring String by using an index to the implicit string reference table.
* Strings are encoding using UTF-8 - however the header may either
* describe a string literal or a string reference.
*
* - string = 0x06 string-data
* - string-data = integer-data [ modified-utf-8 ]
* - modified-utf-8 = *OCTET
*
* @return String
*/
public function readString()
{
$stringReference = $this->readInteger();
//Check if this is a reference string
if (($stringReference & 0x01) == 0) {
// reference string
$stringReference = $stringReference >> 1;
if ($stringReference >= count($this->_referenceStrings)) {
require_once 'Zend/Amf/Exception.php';
throw new Zend_Amf_Exception('Undefined string reference: ' . $stringReference);
}
// reference string found
return $this->_referenceStrings[$stringReference];
}
$length = $stringReference >> 1;
if ($length) {
$string = $this->_stream->readBytes($length);
$this->_referenceStrings[] = $string;
} else {
$string = "";
}
return $string;
}
/**
* Read and deserialize a date
*
* Data is the number of milliseconds elapsed since the epoch
* of midnight, 1st Jan 1970 in the UTC time zone.
* Local time zone information is not sent to flash.
*
* - date = 0x08 integer-data [ number-data ]
*
* @return Zend_Date
*/
public function readDate()
{
$dateReference = $this->readInteger();
if (($dateReference & 0x01) == 0) {
$dateReference = $dateReference >> 1;
if ($dateReference>=count($this->_referenceObjects)) {
require_once 'Zend/Amf/Exception.php';
throw new Zend_Amf_Exception('Undefined date reference: ' . $dateReference);
}
return $this->_referenceObjects[$dateReference];
}
$timestamp = floor($this->_stream->readDouble() / 1000);
require_once 'Zend/Date.php';
$dateTime = new Zend_Date((int) $timestamp);
$this->_referenceObjects[] = $dateTime;
return $dateTime;
}
/**
* Read amf array to PHP array
*
* - array = 0x09 integer-data ( [ 1OCTET *amf3-data ] | [OCTET *amf3-data 1] | [ OCTET *amf-data ] )
*
* @return array
*/
public function readArray()
{
$arrayReference = $this->readInteger();
if (($arrayReference & 0x01)==0){
$arrayReference = $arrayReference >> 1;
if ($arrayReference>=count($this->_referenceObjects)) {
require_once 'Zend/Amf/Exception.php';
throw new Zend_Amf_Exception('Unknow array reference: ' . $arrayReference);
}
return $this->_referenceObjects[$arrayReference];
}
// Create a holder for the array in the reference list
$data = array();
$this->_referenceObjects[] =& $data;
$key = $this->readString();
// Iterating for string based keys.
while ($key != '') {
$data[$key] = $this->readTypeMarker();
$key = $this->readString();
}
$arrayReference = $arrayReference >>1;
//We have a dense array
for ($i=0; $i < $arrayReference; $i++) {
$data[] = $this->readTypeMarker();
}
return $data;
}
/**
* Read an object from the AMF stream and convert it into a PHP object
*
* @todo Rather than using an array of traitsInfo create Zend_Amf_Value_TraitsInfo
* @return object|array
*/
public function readObject()
{
$traitsInfo = $this->readInteger();
$storedObject = ($traitsInfo & 0x01)==0;
$traitsInfo = $traitsInfo >> 1;
// Check if the Object is in the stored Objects reference table
if ($storedObject) {
$ref = $traitsInfo;
if (!isset($this->_referenceObjects[$ref])) {
require_once 'Zend/Amf/Exception.php';
throw new Zend_Amf_Exception('Unknown Object reference: ' . $ref);
}
$returnObject = $this->_referenceObjects[$ref];
} else {
// Check if the Object is in the stored Definitions reference table
$storedClass = ($traitsInfo & 0x01) == 0;
$traitsInfo = $traitsInfo >> 1;
if ($storedClass) {
$ref = $traitsInfo;
if (!isset($this->_referenceDefinitions[$ref])) {
require_once 'Zend/Amf/Exception.php';
throw new Zend_Amf_Exception('Unknows Definition reference: '. $ref);
}
// Populate the reference attributes
$className = $this->_referenceDefinitions[$ref]['className'];
$encoding = $this->_referenceDefinitions[$ref]['encoding'];
$propertyNames = $this->_referenceDefinitions[$ref]['propertyNames'];
} else {
// The class was not in the reference tables. Start reading rawdata to build traits.
// Create a traits table. Zend_Amf_Value_TraitsInfo would be ideal
$className = $this->readString();
$encoding = $traitsInfo & 0x03;
$propertyNames = array();
$traitsInfo = $traitsInfo >> 2;
}
// We now have the object traits defined in variables. Time to go to work:
if (!$className) {
// No class name generic object
$returnObject = new stdClass();
} else {
// Defined object
// Typed object lookup against registered classname maps
if ($loader = Zend_Amf_Parse_TypeLoader::loadType($className)) {
$returnObject = new $loader();
} else {
//user defined typed object
require_once 'Zend/Amf/Exception.php';
throw new Zend_Amf_Exception('Typed object not found: '. $className . ' ');
}
}
// Add the Object to the reference table
$this->_referenceObjects[] = $returnObject;
$properties = array(); // clear value
// Check encoding types for additional processing.
switch ($encoding) {
case (Zend_Amf_Constants::ET_EXTERNAL):
// Externalizable object such as {ArrayCollection} and {ObjectProxy}
if (!$storedClass) {
$this->_referenceDefinitions[] = array(
'className' => $className,
'encoding' => $encoding,
'propertyNames' => $propertyNames,
);
}
$returnObject->externalizedData = $this->readTypeMarker();
break;
case (Zend_Amf_Constants::ET_DYNAMIC):
// used for Name-value encoding
if (!$storedClass) {
$this->_referenceDefinitions[] = array(
'className' => $className,
'encoding' => $encoding,
'propertyNames' => $propertyNames,
);
}
// not a reference object read name value properties from byte stream
do {
$property = $this->readString();
if ($property != "") {
$propertyNames[] = $property;
$properties[$property] = $this->readTypeMarker();
}
} while ($property !="");
break;
default:
// basic property list object.
if (!$storedClass) {
$count = $traitsInfo; // Number of properties in the list
for($i=0; $i< $count; $i++) {
$propertyNames[] = $this->readString();
}
// Add a reference to the class.
$this->_referenceDefinitions[] = array(
'className' => $className,
'encoding' => $encoding,
'propertyNames' => $propertyNames,
);
}
foreach ($propertyNames as $property) {
$properties[$property] = $this->readTypeMarker();
}
break;
}
// Add properties back to the return object.
foreach($properties as $key=>$value) {
if($key) {
$returnObject->$key = $value;
}
}
}
if($returnObject instanceof Zend_Amf_Value_Messaging_ArrayCollection) {
if(isset($returnObject->externalizedData)) {
$returnObject = $returnObject->externalizedData;
} else {
$returnObject = get_object_vars($returnObject);
}
}
return $returnObject;
}
/**
* Convert XML to SimpleXml
* If user wants DomDocument they can use dom_import_simplexml
*
* @return SimpleXml Object
*/
public function readXmlString()
{
$xmlReference = $this->readInteger();
$length = $xmlReference >> 1;
$string = $this->_stream->readBytes($length);
return simplexml_load_string($string);
}
}

View File

@@ -0,0 +1,507 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Amf
* @subpackage Parse_Amf3
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Serializer.php 20392 2010-01-18 18:34:23Z stas $
*/
/** Zend_Amf_Constants */
require_once 'Zend/Amf/Constants.php';
/** Zend_Amf_Parse_Serializer */
require_once 'Zend/Amf/Parse/Serializer.php';
/** Zend_Amf_Parse_TypeLoader */
require_once 'Zend/Amf/Parse/TypeLoader.php';
/**
* Detect PHP object type and convert it to a corresponding AMF3 object type
*
* @package Zend_Amf
* @subpackage Parse_Amf3
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Amf_Parse_Amf3_Serializer extends Zend_Amf_Parse_Serializer
{
/**
* An array of reference objects per amf body
* @var array
*/
protected $_referenceObjects = array();
/**
* An array of reference strings per amf body
* @var array
*/
protected $_referenceStrings = array();
/**
* An array of reference class definitions, indexed by classname
* @var array
*/
protected $_referenceDefinitions = array();
/**
* Serialize PHP types to AMF3 and write to stream
*
* Checks to see if the type was declared and then either
* auto negotiates the type or use the user defined markerType to
* serialize the data from php back to AMF3
*
* @param mixed $content
* @param int $markerType
* @return void
*/
public function writeTypeMarker($data, $markerType=null)
{
if (null !== $markerType) {
// Write the Type Marker to denote the following action script data type
$this->_stream->writeByte($markerType);
switch ($markerType) {
case Zend_Amf_Constants::AMF3_NULL:
break;
case Zend_Amf_Constants::AMF3_BOOLEAN_FALSE:
break;
case Zend_Amf_Constants::AMF3_BOOLEAN_TRUE:
break;
case Zend_Amf_Constants::AMF3_INTEGER:
$this->writeInteger($data);
break;
case Zend_Amf_Constants::AMF3_NUMBER:
$this->_stream->writeDouble($data);
break;
case Zend_Amf_Constants::AMF3_STRING:
$this->writeString($data);
break;
case Zend_Amf_Constants::AMF3_DATE:
$this->writeDate($data);
break;
case Zend_Amf_Constants::AMF3_ARRAY:
$this->writeArray($data);
break;
case Zend_Amf_Constants::AMF3_OBJECT:
$this->writeObject($data);
break;
case Zend_Amf_Constants::AMF3_BYTEARRAY:
$this->writeByteArray($data);
break;
case Zend_Amf_Constants::AMF3_XMLSTRING;
$this->writeXml($data);
break;
default:
require_once 'Zend/Amf/Exception.php';
throw new Zend_Amf_Exception('Unknown Type Marker: ' . $markerType);
}
} else {
// Detect Type Marker
if(is_resource($data)) {
$data = Zend_Amf_Parse_TypeLoader::handleResource($data);
}
switch (true) {
case (null === $data):
$markerType = Zend_Amf_Constants::AMF3_NULL;
break;
case (is_bool($data)):
if ($data){
$markerType = Zend_Amf_Constants::AMF3_BOOLEAN_TRUE;
} else {
$markerType = Zend_Amf_Constants::AMF3_BOOLEAN_FALSE;
}
break;
case (is_int($data)):
if (($data > 0xFFFFFFF) || ($data < -268435456)) {
$markerType = Zend_Amf_Constants::AMF3_NUMBER;
} else {
$markerType = Zend_Amf_Constants::AMF3_INTEGER;
}
break;
case (is_float($data)):
$markerType = Zend_Amf_Constants::AMF3_NUMBER;
break;
case (is_string($data)):
$markerType = Zend_Amf_Constants::AMF3_STRING;
break;
case (is_array($data)):
$markerType = Zend_Amf_Constants::AMF3_ARRAY;
break;
case (is_object($data)):
// Handle object types.
if (($data instanceof DateTime) || ($data instanceof Zend_Date)) {
$markerType = Zend_Amf_Constants::AMF3_DATE;
} else if ($data instanceof Zend_Amf_Value_ByteArray) {
$markerType = Zend_Amf_Constants::AMF3_BYTEARRAY;
} else if (($data instanceof DOMDocument) || ($data instanceof SimpleXMLElement)) {
$markerType = Zend_Amf_Constants::AMF3_XMLSTRING;
} else {
$markerType = Zend_Amf_Constants::AMF3_OBJECT;
}
break;
default:
require_once 'Zend/Amf/Exception.php';
throw new Zend_Amf_Exception('Unsupported data type: ' . gettype($data));
}
$this->writeTypeMarker($data, $markerType);
}
}
/**
* Write an AMF3 integer
*
* @param int|float $data
* @return Zend_Amf_Parse_Amf3_Serializer
*/
public function writeInteger($int)
{
if (($int & 0xffffff80) == 0) {
$this->_stream->writeByte($int & 0x7f);
return $this;
}
if (($int & 0xffffc000) == 0 ) {
$this->_stream->writeByte(($int >> 7 ) | 0x80);
$this->_stream->writeByte($int & 0x7f);
return $this;
}
if (($int & 0xffe00000) == 0) {
$this->_stream->writeByte(($int >> 14 ) | 0x80);
$this->_stream->writeByte(($int >> 7 ) | 0x80);
$this->_stream->writeByte($int & 0x7f);
return $this;
}
$this->_stream->writeByte(($int >> 22 ) | 0x80);
$this->_stream->writeByte(($int >> 15 ) | 0x80);
$this->_stream->writeByte(($int >> 8 ) | 0x80);
$this->_stream->writeByte($int & 0xff);
return $this;
}
/**
* Send string to output stream, without trying to reference it.
* The string is prepended with strlen($string) << 1 | 0x01
*
* @param string $string
* @return Zend_Amf_Parse_Amf3_Serializer
*/
protected function writeBinaryString($string){
$ref = strlen($string) << 1 | 0x01;
$this->writeInteger($ref);
$this->_stream->writeBytes($string);
return $this;
}
/**
* Send string to output stream
*
* @param string $string
* @return Zend_Amf_Parse_Amf3_Serializer
*/
public function writeString($string)
{
$len = strlen($string);
if(!$len){
$this->writeInteger(0x01);
return $this;
}
$ref = array_search($string, $this->_referenceStrings, true);
if($ref === false){
$this->_referenceStrings[] = $string;
$this->writeBinaryString($string);
} else {
$ref <<= 1;
$this->writeInteger($ref);
}
return $this;
}
/**
* Send ByteArray to output stream
*
* @param string|Zend_Amf_Value_ByteArray $data
* @return Zend_Amf_Parse_Amf3_Serializer
*/
public function writeByteArray($data){
if($this->writeObjectReference($data)){
return $this;
}
if(is_string($data)) {
//nothing to do
} else if ($data instanceof Zend_Amf_Value_ByteArray) {
$data = $data->getData();
} else {
require_once 'Zend/Amf/Exception.php';
throw new Zend_Amf_Exception('Invalid ByteArray specified; must be a string or Zend_Amf_Value_ByteArray');
}
$this->writeBinaryString($data);
return $this;
}
/**
* Send xml to output stream
*
* @param DOMDocument|SimpleXMLElement $xml
* @return Zend_Amf_Parse_Amf3_Serializer
*/
public function writeXml($xml)
{
if($this->writeObjectReference($xml)){
return $this;
}
if(is_string($xml)) {
//nothing to do
} else if ($xml instanceof DOMDocument) {
$xml = $xml->saveXml();
} else if ($xml instanceof SimpleXMLElement) {
$xml = $xml->asXML();
} else {
require_once 'Zend/Amf/Exception.php';
throw new Zend_Amf_Exception('Invalid xml specified; must be a DOMDocument or SimpleXMLElement');
}
$this->writeBinaryString($xml);
return $this;
}
/**
* Convert DateTime/Zend_Date to AMF date
*
* @param DateTime|Zend_Date $date
* @return Zend_Amf_Parse_Amf3_Serializer
*/
public function writeDate($date)
{
if($this->writeObjectReference($date)){
return $this;
}
if ($date instanceof DateTime) {
$dateString = $date->format('U') * 1000;
} elseif ($date instanceof Zend_Date) {
$dateString = $date->toString('U') * 1000;
} else {
require_once 'Zend/Amf/Exception.php';
throw new Zend_Amf_Exception('Invalid date specified; must be a string DateTime or Zend_Date object');
}
$this->writeInteger(0x01);
// write time to stream minus milliseconds
$this->_stream->writeDouble($dateString);
return $this;
}
/**
* Write a PHP array back to the amf output stream
*
* @param array $array
* @return Zend_Amf_Parse_Amf3_Serializer
*/
public function writeArray(array $array)
{
// arrays aren't reference here but still counted
$this->_referenceObjects[] = $array;
// have to seperate mixed from numberic keys.
$numeric = array();
$string = array();
foreach ($array as $key => $value) {
if (is_int($key)) {
$numeric[] = $value;
} else {
$string[$key] = $value;
}
}
// write the preamble id of the array
$length = count($numeric);
$id = ($length << 1) | 0x01;
$this->writeInteger($id);
//Write the mixed type array to the output stream
foreach($string as $key => $value) {
$this->writeString($key)
->writeTypeMarker($value);
}
$this->writeString('');
// Write the numeric array to ouput stream
foreach($numeric as $value) {
$this->writeTypeMarker($value);
}
return $this;
}
/**
* Check if the given object is in the reference table, write the reference if it exists,
* otherwise add the object to the reference table
*
* @param mixed $object object to check for reference
* @return Boolean true, if the reference was written, false otherwise
*/
protected function writeObjectReference($object)
{
$ref = array_search($object, $this->_referenceObjects,true);
//quickly handle object references
if($ref !== false){
$ref <<= 1;
$this->writeInteger($ref);
return true;
}
$this->_referenceObjects[] = $object;
return false;
}
/**
* Write object to ouput stream
*
* @param mixed $data
* @return Zend_Amf_Parse_Amf3_Serializer
*/
public function writeObject($object)
{
if($this->writeObjectReference($object)){
return $this;
}
$className = '';
//Check to see if the object is a typed object and we need to change
switch (true) {
// the return class mapped name back to actionscript class name.
case ($className = Zend_Amf_Parse_TypeLoader::getMappedClassName(get_class($object))):
break;
// Check to see if the user has defined an explicit Action Script type.
case isset($object->_explicitType):
$className = $object->_explicitType;
break;
// Check if user has defined a method for accessing the Action Script type
case method_exists($object, 'getASClassName'):
$className = $object->getASClassName();
break;
// No return class name is set make it a generic object
case ($object instanceof stdClass):
$className = '';
break;
// By default, use object's class name
default:
$className = get_class($object);
break;
}
$writeTraits = true;
//check to see, if we have a corresponding definition
if(array_key_exists($className, $this->_referenceDefinitions)){
$traitsInfo = $this->_referenceDefinitions[$className]['id'];
$encoding = $this->_referenceDefinitions[$className]['encoding'];
$propertyNames = $this->_referenceDefinitions[$className]['propertyNames'];
$traitsInfo = ($traitsInfo << 2) | 0x01;
$writeTraits = false;
} else {
$propertyNames = array();
if($className == ''){
//if there is no className, we interpret the class as dynamic without any sealed members
$encoding = Zend_Amf_Constants::ET_DYNAMIC;
} else {
$encoding = Zend_Amf_Constants::ET_PROPLIST;
foreach($object as $key => $value) {
if( $key[0] != "_") {
$propertyNames[] = $key;
}
}
}
$this->_referenceDefinitions[$className] = array(
'id' => count($this->_referenceDefinitions),
'encoding' => $encoding,
'propertyNames' => $propertyNames,
);
$traitsInfo = Zend_Amf_Constants::AMF3_OBJECT_ENCODING;
$traitsInfo |= $encoding << 2;
$traitsInfo |= (count($propertyNames) << 4);
}
$this->writeInteger($traitsInfo);
if($writeTraits){
$this->writeString($className);
foreach ($propertyNames as $value) {
$this->writeString($value);
}
}
try {
switch($encoding) {
case Zend_Amf_Constants::ET_PROPLIST:
//Write the sealed values to the output stream.
foreach ($propertyNames as $key) {
$this->writeTypeMarker($object->$key);
}
break;
case Zend_Amf_Constants::ET_DYNAMIC:
//Write the sealed values to the output stream.
foreach ($propertyNames as $key) {
$this->writeTypeMarker($object->$key);
}
//Write remaining properties
foreach($object as $key => $value){
if(!in_array($key,$propertyNames) && $key[0] != "_"){
$this->writeString($key);
$this->writeTypeMarker($value);
}
}
//Write an empty string to end the dynamic part
$this->writeString('');
break;
case Zend_Amf_Constants::ET_EXTERNAL:
require_once 'Zend/Amf/Exception.php';
throw new Zend_Amf_Exception('External Object Encoding not implemented');
break;
default:
require_once 'Zend/Amf/Exception.php';
throw new Zend_Amf_Exception('Unknown Object Encoding type: ' . $encoding);
}
} catch (Exception $e) {
require_once 'Zend/Amf/Exception.php';
throw new Zend_Amf_Exception('Unable to writeObject output: ' . $e->getMessage(), 0, $e);
}
return $this;
}
}

View File

@@ -0,0 +1,65 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Amf
* @subpackage Parse
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Deserializer.php 20096 2010-01-06 02:05:09Z bkarwin $
*/
/**
* Abstract cass that all deserializer must implement.
*
* Logic for deserialization of the AMF envelop is based on resources supplied
* by Adobe Blaze DS. For and example of deserialization please review the BlazeDS
* source tree.
*
* @see http://opensource.adobe.com/svn/opensource/blazeds/trunk/modules/core/src/java/flex/messaging/io/amf/
* @package Zend_Amf
* @subpackage Parse
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
abstract class Zend_Amf_Parse_Deserializer
{
/**
* The raw string that represents the AMF request.
*
* @var Zend_Amf_Parse_InputStream
*/
protected $_stream;
/**
* Constructor
*
* @param Zend_Amf_Parse_InputStream $stream
* @return void
*/
public function __construct(Zend_Amf_Parse_InputStream $stream)
{
$this->_stream = $stream;
}
/**
* Checks for AMF marker types and calls the appropriate methods
* for deserializing those marker types. Markers are the data type of
* the following value.
*
* @param int $typeMarker
* @return mixed Whatever the data type is of the marker in php
*/
public abstract function readTypeMarker($markerType = null);
}

View File

@@ -0,0 +1,39 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Amf
* @subpackage Parse
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: InputStream.php 20096 2010-01-06 02:05:09Z bkarwin $
*/
/** Zend_Amf_Util_BinaryStream */
require_once 'Zend/Amf/Util/BinaryStream.php';
/**
* InputStream is used to iterate at a binary level through the AMF request.
*
* InputStream extends BinaryStream as eventually BinaryStream could be placed
* outside of Zend_Amf in order to allow other packages to use the class.
*
* @package Zend_Amf
* @subpackage Parse
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Amf_Parse_InputStream extends Zend_Amf_Util_BinaryStream
{
}

View File

@@ -0,0 +1,49 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Amf
* @subpackage Parse
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: OutputStream.php 20096 2010-01-06 02:05:09Z bkarwin $
*/
/** Zend_Amf_Util_BinaryStream */
require_once 'Zend/Amf/Util/BinaryStream.php';
/**
* Iterate at a binary level through the AMF response
*
* OutputStream extends BinaryStream as eventually BinaryStream could be placed
* outside of Zend_Amf in order to allow other packages to use the class.
*
* @uses Zend_Amf_Util_BinaryStream
* @package Zend_Amf
* @subpackage Parse
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Amf_Parse_OutputStream extends Zend_Amf_Util_BinaryStream
{
/**
* Constructor
*
* @return void
*/
public function __construct()
{
parent::__construct('');
}
}

View File

@@ -0,0 +1,59 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Amf
* @subpackage Parse
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Serializer.php 21210 2010-02-27 10:37:39Z yoshida@zend.co.jp $
*/
/**
* Base abstract class for all AMF serializers.
*
* @package Zend_Amf
* @subpackage Parse
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
abstract class Zend_Amf_Parse_Serializer
{
/**
* Reference to the current output stream being constructed
*
* @var string
*/
protected $_stream;
/**
* Constructor
*
* @param Zend_Amf_Parse_OutputStream $stream
* @return void
*/
public function __construct(Zend_Amf_Parse_OutputStream $stream)
{
$this->_stream = $stream;
}
/**
* Find the PHP object type and convert it into an AMF object type
*
* @param mixed $content
* @param int $markerType
* @return void
*/
public abstract function writeTypeMarker($content, $markerType=null);
}

View File

@@ -0,0 +1,231 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Amf
* @subpackage Parse
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: TypeLoader.php 20096 2010-01-06 02:05:09Z bkarwin $
*/
/**
* @see Zend_Amf_Value_Messaging_AcknowledgeMessage
*/
require_once 'Zend/Amf/Value/Messaging/AcknowledgeMessage.php';
/**
* @see Zend_Amf_Value_Messaging_AsyncMessage
*/
require_once 'Zend/Amf/Value/Messaging/AsyncMessage.php';
/**
* @see Zend_Amf_Value_Messaging_CommandMessage
*/
require_once 'Zend/Amf/Value/Messaging/CommandMessage.php';
/**
* @see Zend_Amf_Value_Messaging_ErrorMessage
*/
require_once 'Zend/Amf/Value/Messaging/ErrorMessage.php';
/**
* @see Zend_Amf_Value_Messaging_RemotingMessage
*/
require_once 'Zend/Amf/Value/Messaging/RemotingMessage.php';
/**
* Loads a local class and executes the instantiation of that class.
*
* @todo PHP 5.3 can drastically change this class w/ namespace and the new call_user_func w/ namespace
* @package Zend_Amf
* @subpackage Parse
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
final class Zend_Amf_Parse_TypeLoader
{
/**
* @var string callback class
*/
public static $callbackClass;
/**
* @var array AMF class map
*/
public static $classMap = array (
'flex.messaging.messages.AcknowledgeMessage' => 'Zend_Amf_Value_Messaging_AcknowledgeMessage',
'flex.messaging.messages.ErrorMessage' => 'Zend_Amf_Value_Messaging_AsyncMessage',
'flex.messaging.messages.CommandMessage' => 'Zend_Amf_Value_Messaging_CommandMessage',
'flex.messaging.messages.ErrorMessage' => 'Zend_Amf_Value_Messaging_ErrorMessage',
'flex.messaging.messages.RemotingMessage' => 'Zend_Amf_Value_Messaging_RemotingMessage',
'flex.messaging.io.ArrayCollection' => 'Zend_Amf_Value_Messaging_ArrayCollection',
);
/**
* @var array Default class map
*/
protected static $_defaultClassMap = array(
'flex.messaging.messages.AcknowledgeMessage' => 'Zend_Amf_Value_Messaging_AcknowledgeMessage',
'flex.messaging.messages.ErrorMessage' => 'Zend_Amf_Value_Messaging_AsyncMessage',
'flex.messaging.messages.CommandMessage' => 'Zend_Amf_Value_Messaging_CommandMessage',
'flex.messaging.messages.ErrorMessage' => 'Zend_Amf_Value_Messaging_ErrorMessage',
'flex.messaging.messages.RemotingMessage' => 'Zend_Amf_Value_Messaging_RemotingMessage',
'flex.messaging.io.ArrayCollection' => 'Zend_Amf_Value_Messaging_ArrayCollection',
);
/**
* @var Zend_Loader_PluginLoader_Interface
*/
protected static $_resourceLoader = null;
/**
* Load the mapped class type into a callback.
*
* @param string $className
* @return object|false
*/
public static function loadType($className)
{
$class = self::getMappedClassName($className);
if(!$class) {
$class = str_replace('.', '_', $className);
}
if (!class_exists($class)) {
return "stdClass";
}
return $class;
}
/**
* Looks up the supplied call name to its mapped class name
*
* @param string $className
* @return string
*/
public static function getMappedClassName($className)
{
$mappedName = array_search($className, self::$classMap);
if ($mappedName) {
return $mappedName;
}
$mappedName = array_search($className, array_flip(self::$classMap));
if ($mappedName) {
return $mappedName;
}
return false;
}
/**
* Map PHP class names to ActionScript class names
*
* Allows users to map the class names of there action script classes
* to the equivelent php class name. Used in deserialization to load a class
* and serialiation to set the class name of the returned object.
*
* @param string $asClassName
* @param string $phpClassName
* @return void
*/
public static function setMapping($asClassName, $phpClassName)
{
self::$classMap[$asClassName] = $phpClassName;
}
/**
* Reset type map
*
* @return void
*/
public static function resetMap()
{
self::$classMap = self::$_defaultClassMap;
}
/**
* Set loader for resource type handlers
*
* @param Zend_Loader_PluginLoader_Interface $loader
*/
public static function setResourceLoader(Zend_Loader_PluginLoader_Interface $loader)
{
self::$_resourceLoader = $loader;
}
/**
* Add directory to the list of places where to look for resource handlers
*
* @param string $prefix
* @param string $dir
*/
public static function addResourceDirectory($prefix, $dir)
{
if(self::$_resourceLoader) {
self::$_resourceLoader->addPrefixPath($prefix, $dir);
}
}
/**
* Get plugin class that handles this resource
*
* @param resource $resource Resource type
* @return string Class name
*/
public static function getResourceParser($resource)
{
if(self::$_resourceLoader) {
$type = preg_replace("/[^A-Za-z0-9_]/", " ", get_resource_type($resource));
$type = str_replace(" ","", ucwords($type));
return self::$_resourceLoader->load($type);
}
return false;
}
/**
* Convert resource to a serializable object
*
* @param resource $resource
* @return mixed
*/
public static function handleResource($resource)
{
if(!self::$_resourceLoader) {
require_once 'Zend/Amf/Exception.php';
throw new Zend_Amf_Exception('Unable to handle resources - resource plugin loader not set');
}
try {
while(is_resource($resource)) {
$resclass = self::getResourceParser($resource);
if(!$resclass) {
require_once 'Zend/Amf/Exception.php';
throw new Zend_Amf_Exception('Can not serialize resource type: '. get_resource_type($resource));
}
$parser = new $resclass();
if(is_callable(array($parser, 'parse'))) {
$resource = $parser->parse($resource);
} else {
require_once 'Zend/Amf/Exception.php';
throw new Zend_Amf_Exception("Could not call parse() method on class $resclass");
}
}
return $resource;
} catch(Zend_Amf_Exception $e) {
throw new Zend_Amf_Exception($e->getMessage(), $e->getCode(), $e);
} catch(Exception $e) {
require_once 'Zend/Amf/Exception.php';
throw new Zend_Amf_Exception('Can not serialize resource type: '. get_resource_type($resource), 0, $e);
}
}
}

View File

@@ -0,0 +1,285 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Amf
* @subpackage Util
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: BinaryStream.php 21210 2010-02-27 10:37:39Z yoshida@zend.co.jp $
*/
/**
* Utility class to walk through a data stream byte by byte with conventional names
*
* @package Zend_Amf
* @subpackage Util
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Amf_Util_BinaryStream
{
/**
* @var string Byte stream
*/
protected $_stream;
/**
* @var int Length of stream
*/
protected $_streamLength;
/**
* @var bool BigEndian encoding?
*/
protected $_bigEndian;
/**
* @var int Current position in stream
*/
protected $_needle;
/**
* Constructor
*
* Create a reference to a byte stream that is going to be parsed or created
* by the methods in the class. Detect if the class should use big or
* little Endian encoding.
*
* @param string $stream use '' if creating a new stream or pass a string if reading.
* @return void
*/
public function __construct($stream)
{
if (!is_string($stream)) {
require_once 'Zend/Amf/Exception.php';
throw new Zend_Amf_Exception('Inputdata is not of type String');
}
$this->_stream = $stream;
$this->_needle = 0;
$this->_streamLength = strlen($stream);
$this->_bigEndian = (pack('l', 1) === "\x00\x00\x00\x01");
}
/**
* Returns the current stream
*
* @return string
*/
public function getStream()
{
return $this->_stream;
}
/**
* Read the number of bytes in a row for the length supplied.
*
* @todo Should check that there are enough bytes left in the stream we are about to read.
* @param int $length
* @return string
* @throws Zend_Amf_Exception for buffer underrun
*/
public function readBytes($length)
{
if (($length + $this->_needle) > $this->_streamLength) {
require_once 'Zend/Amf/Exception.php';
throw new Zend_Amf_Exception('Buffer underrun at needle position: ' . $this->_needle . ' while requesting length: ' . $length);
}
$bytes = substr($this->_stream, $this->_needle, $length);
$this->_needle+= $length;
return $bytes;
}
/**
* Write any length of bytes to the stream
*
* Usually a string.
*
* @param string $bytes
* @return Zend_Amf_Util_BinaryStream
*/
public function writeBytes($bytes)
{
$this->_stream.= $bytes;
return $this;
}
/**
* Reads a signed byte
*
* @return int Value is in the range of -128 to 127.
*/
public function readByte()
{
if (($this->_needle + 1) > $this->_streamLength) {
require_once 'Zend/Amf/Exception.php';
throw new Zend_Amf_Exception('Buffer underrun at needle position: ' . $this->_needle . ' while requesting length: ' . $length);
}
return ord($this->_stream{$this->_needle++});
}
/**
* Writes the passed string into a signed byte on the stream.
*
* @param string $stream
* @return Zend_Amf_Util_BinaryStream
*/
public function writeByte($stream)
{
$this->_stream.= pack('c', $stream);
return $this;
}
/**
* Reads a signed 32-bit integer from the data stream.
*
* @return int Value is in the range of -2147483648 to 2147483647
*/
public function readInt()
{
return ($this->readByte() << 8) + $this->readByte();
}
/**
* Write an the integer to the output stream as a 32 bit signed integer
*
* @param int $stream
* @return Zend_Amf_Util_BinaryStream
*/
public function writeInt($stream)
{
$this->_stream.= pack('n', $stream);
return $this;
}
/**
* Reads a UTF-8 string from the data stream
*
* @return string A UTF-8 string produced by the byte representation of characters
*/
public function readUtf()
{
$length = $this->readInt();
return $this->readBytes($length);
}
/**
* Wite a UTF-8 string to the outputstream
*
* @param string $stream
* @return Zend_Amf_Util_BinaryStream
*/
public function writeUtf($stream)
{
$this->writeInt(strlen($stream));
$this->_stream.= $stream;
return $this;
}
/**
* Read a long UTF string
*
* @return string
*/
public function readLongUtf()
{
$length = $this->readLong();
return $this->readBytes($length);
}
/**
* Write a long UTF string to the buffer
*
* @param string $stream
* @return Zend_Amf_Util_BinaryStream
*/
public function writeLongUtf($stream)
{
$this->writeLong(strlen($stream));
$this->_stream.= $stream;
}
/**
* Read a long numeric value
*
* @return double
*/
public function readLong()
{
return ($this->readByte() << 24) + ($this->readByte() << 16) + ($this->readByte() << 8) + $this->readByte();
}
/**
* Write long numeric value to output stream
*
* @param int|string $stream
* @return Zend_Amf_Util_BinaryStream
*/
public function writeLong($stream)
{
$this->_stream.= pack('N', $stream);
return $this;
}
/**
* Read a 16 bit unsigned short.
*
* @todo This could use the unpack() w/ S,n, or v
* @return double
*/
public function readUnsignedShort()
{
$byte1 = $this->readByte();
$byte2 = $this->readByte();
return (($byte1 << 8) | $byte2);
}
/**
* Reads an IEEE 754 double-precision floating point number from the data stream.
*
* @return double Floating point number
*/
public function readDouble()
{
$bytes = substr($this->_stream, $this->_needle, 8);
$this->_needle+= 8;
if (!$this->_bigEndian) {
$bytes = strrev($bytes);
}
$double = unpack('dflt', $bytes);
return $double['flt'];
}
/**
* Writes an IEEE 754 double-precision floating point number from the data stream.
*
* @param string|double $stream
* @return Zend_Amf_Util_BinaryStream
*/
public function writeDouble($stream)
{
$stream = pack('d', $stream);
if (!$this->_bigEndian) {
$stream = strrev($stream);
}
$this->_stream.= $stream;
return $this;
}
}

View File

@@ -0,0 +1,92 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Amf
* @subpackage Value
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: AbstractMessage.php 20096 2010-01-06 02:05:09Z bkarwin $
*/
/**
* This is the default Implementation of Message, which provides
* a convenient base for behavior and association of common endpoints
*
* @package Zend_Amf
* @subpackage Value
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Amf_Value_Messaging_AbstractMessage
{
/**
* @var string Client identifier
*/
public $clientId;
/**
* @var string Destination
*/
public $destination;
/**
* @var string Message identifier
*/
public $messageId;
/**
* @var int Message timestamp
*/
public $timestamp;
/**
* @var int Message TTL
*/
public $timeToLive;
/**
* @var object Message headers
*/
public $headers;
/**
* @var string Message body
*/
public $body;
/**
* generate a unique id
*
* Format is: ########-####-####-####-############
* Where # is an uppercase letter or number
* example: 6D9DC7EC-A273-83A9-ABE3-00005FD752D6
*
* @return string
*/
public function generateId()
{
return sprintf(
'%08X-%04X-%04X-%02X%02X-%012X',
mt_rand(),
mt_rand(0, 65535),
bindec(substr_replace(
sprintf('%016b', mt_rand(0, 65535)), '0100', 11, 4)
),
bindec(substr_replace(sprintf('%08b', mt_rand(0, 255)), '01', 5, 2)),
mt_rand(0, 255),
mt_rand()
);
}
}

View File

@@ -0,0 +1,60 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Amf
* @subpackage Value
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: AcknowledgeMessage.php 20096 2010-01-06 02:05:09Z bkarwin $
*/
/** Zend_Amf_Value_Messaging_AsyncMessage */
require_once 'Zend/Amf/Value/Messaging/AsyncMessage.php';
/**
* This is the type of message returned by the MessageBroker
* to endpoints after the broker has routed an endpoint's message
* to a service.
*
* flex.messaging.messages.AcknowledgeMessage
*
* @package Zend_Amf
* @subpackage Value
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Amf_Value_Messaging_AcknowledgeMessage extends Zend_Amf_Value_Messaging_AsyncMessage
{
/**
* Create a new Acknowledge Message
*
* @param unknown_type $message
*/
public function __construct($message)
{
$this->clientId = $this->generateId();
$this->destination = null;
$this->messageId = $this->generateId();
$this->timestamp = time().'00';
$this->timeToLive = 0;
$this->headers = new STDClass();
$this->body = null;
// correleate the two messages
if ($message && isset($message->messageId)) {
$this->correlationId = $message->messageId;
}
}
}

View File

@@ -0,0 +1,43 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Amf
* @subpackage Value
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: AsyncMessage.php 20096 2010-01-06 02:05:09Z bkarwin $
*/
/** Zend_Amf_Value_Messaging_AbstractMessage */
require_once 'Zend/Amf/Value/Messaging/AbstractMessage.php';
/**
* This type of message contains information necessary to perform
* point-to-point or publish-subscribe messaging.
*
* @package Zend_Amf
* @subpackage Value
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Amf_Value_Messaging_AsyncMessage extends Zend_Amf_Value_Messaging_AbstractMessage
{
/**
* The message id to be responded to.
* @var String
*/
public $correlationId;
}

View File

@@ -0,0 +1,119 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Amf
* @subpackage Value
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: CommandMessage.php 20096 2010-01-06 02:05:09Z bkarwin $
*/
/**
* @see Zend_Amf_Value_Messaging_AsyncMessage
*/
require_once 'Zend/Amf/Value/Messaging/AsyncMessage.php';
/**
* A message that represents an infrastructure command passed between
* client and server. Subscribe/unsubscribe operations result in
* CommandMessage transmissions, as do polling operations.
*
* Corresponds to flex.messaging.messages.CommandMessage
*
* Note: THESE VALUES MUST BE THE SAME ON CLIENT AND SERVER
*
* @package Zend_Amf
* @subpackage Value
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Amf_Value_Messaging_CommandMessage extends Zend_Amf_Value_Messaging_AsyncMessage
{
/**
* This operation is used to subscribe to a remote destination.
*/
const SUBSCRIBE_OPERATION = 0;
/**
* This operation is used to unsubscribe from a remote destination.
*/
const UNSUSBSCRIBE_OPERATION = 1;
/**
* This operation is used to poll a remote destination for pending,
* undelivered messages.
*/
const POLL_OPERATION = 2;
/**
* This operation is used by a remote destination to sync missed or cached messages
* back to a client as a result of a client issued poll command.
*/
const CLIENT_SYNC_OPERATION = 4;
/**
* This operation is used to test connectivity over the current channel to
* the remote endpoint.
*/
const CLIENT_PING_OPERATION = 5;
/**
* This operation is used to request a list of failover endpoint URIs
* for the remote destination based on cluster membership.
*/
const CLUSTER_REQUEST_OPERATION = 7;
/**
* This operation is used to send credentials to the endpoint so that
* the user can be logged in over the current channel.
* The credentials need to be Base64 encoded and stored in the <code>body</code>
* of the message.
*/
const LOGIN_OPERATION = 8;
/**
* This operation is used to log the user out of the current channel, and
* will invalidate the server session if the channel is HTTP based.
*/
const LOGOUT_OPERATION = 9;
/**
* This operation is used to indicate that the client's subscription to a
* remote destination has been invalidated.
*/
const SESSION_INVALIDATE_OPERATION = 10;
/**
* This operation is used by the MultiTopicConsumer to subscribe/unsubscribe
* from multiple subtopics/selectors in the same message.
*/
const MULTI_SUBSCRIBE_OPERATION = 11;
/**
* This operation is used to indicate that a channel has disconnected
*/
const DISCONNECT_OPERATION = 12;
/**
* This is the default operation for new CommandMessage instances.
*/
const UNKNOWN_OPERATION = 10000;
/**
* The operation to execute for messages of this type
* @var int
*/
public $operation = self::UNKNOWN_OPERATION;
}

View File

@@ -0,0 +1,67 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Amf
* @subpackage Value
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: ErrorMessage.php 20096 2010-01-06 02:05:09Z bkarwin $
*/
/** @see Zend_Amf_Value_Messaging_AcknowledgeMessage */
require_once 'Zend/Amf/Value/Messaging/AcknowledgeMessage.php';
/**
* Creates the error message to report to flex the issue with the call
*
* Corresponds to flex.messaging.messages.ErrorMessage
*
* @package Zend_Amf
* @subpackage Value
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Amf_Value_Messaging_ErrorMessage extends Zend_Amf_Value_Messaging_AcknowledgeMessage
{
/**
* Additional data with error
* @var object
*/
public $extendedData = null;
/**
* Error code number
* @var string
*/
public $faultCode;
/**
* Description as to the cause of the error
* @var string
*/
public $faultDetail;
/**
* Short description of error
* @var string
*/
public $faultString = '';
/**
* root cause of error
* @var object
*/
public $rootCause = null;
}

View File

@@ -0,0 +1,73 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Amf
* @subpackage Value
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: RemotingMessage.php 20096 2010-01-06 02:05:09Z bkarwin $
*/
/** Zend_Amf_Value_Messaging_AbstractMessage */
require_once 'Zend/Amf/Value/Messaging/AbstractMessage.php';
/**
* This type of message contains information needed to perform
* a Remoting invocation.
*
* Corresponds to flex.messaging.messages.RemotingMessage
*
* @package Zend_Amf
* @subpackage Value
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Amf_Value_Messaging_RemotingMessage extends Zend_Amf_Value_Messaging_AbstractMessage
{
/**
* The name of the service to be called including package name
* @var String
*/
public $source;
/**
* The name of the method to be called
* @var string
*/
public $operation;
/**
* The arguments to call the mathod with
* @var array
*/
public $parameters;
/**
* Create a new Remoting Message
*
* @return void
*/
public function __construct()
{
$this->clientId = $this->generateId();
$this->destination = null;
$this->messageId = $this->generateId();
$this->timestamp = time().'00';
$this->timeToLive = 0;
$this->headers = new stdClass();
$this->body = null;
}
}

View File

@@ -0,0 +1,70 @@
<?php
/**
* AMF Binary Format for Restler Framework.
* Native format supported by Adobe Flash and Adobe AIR
* @category Framework
* @package restler
* @subpackage format
* @author R.Arul Kumaran <arul@luracast.com>
* @copyright 2010 Luracast
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link http://luracast.com/products/restler/
*/
class AmfFormat implements iFormat
{
const PATH = '/Zend/Amf/Parse/';
const MIME = 'application/x-amf';
const EXTENSION = 'amf';
public $path = '';
public function init(){
$this->path = dirname(__FILE__);
$include_path = get_include_path();
if(strpos($include_path, 'Zend')===FALSE){
set_include_path($this->path.':'.$include_path);
}
$this->path .= AmfFormat::PATH;
}
public function getMIMEMap()
{
return array(AmfFormat::EXTENSION=>AmfFormat::MIME);
}
public function getMIME(){
return AmfFormat::MIME;
}
public function getExtension(){
return AmfFormat::EXTENSION;
}
public function setMIME($mime){
//do nothing
}
public function setExtension($extension){
//do nothing
}
public function encode($data, $human_readable=false){
$this->init();
require_once $this->path . 'OutputStream.php';
require_once $this->path . 'Amf3/Serializer.php';
$stream = new Zend_Amf_Parse_OutputStream();
$serializer = new Zend_Amf_Parse_Amf3_Serializer($stream);
$serializer->writeTypeMarker($data);
return $stream->getStream();
}
public function decode($data){
$this->init();
require_once $this->path .'InputStream.php';
require_once $this->path .'Amf3/Deserializer.php';
$stream = new Zend_Amf_Parse_InputStream(substr($data, 1));
$deserializer = new Zend_Amf_Parse_Amf3_Deserializer($stream);
return $deserializer->readTypeMarker();
}
public function __toString(){
return $this->getExtension();
}
}

58
gulliver/thirdparty/restler/compat.php vendored Normal file
View File

@@ -0,0 +1,58 @@
<?php
if(version_compare('5.0.0',PHP_VERSION)>0){
die('Restler requires PHP 5.x.x');
}
#requires 5.3.2
if(!method_exists('ReflectionMethod', 'setAccessible')){
#echo'RESTLER_METHOD_UNPROTECTION_MODE';
function isRestlerCompatibilityModeEnabled(){
return TRUE;
}
function unprotect($method_info){
$class_name = $method_info->class_name;
$method = $method_info->method_name;
$params = $method_info->arguments;
$unique = uniqid('Dynamic')."_";
$class_code = "class $unique$class_name extends $class_name {";
$p = array();
for ($i = 0; $i < count($params); $i++) {
$p[]='$'."P$i";
}
$p = implode(',', $p);
$class_code .= "function $unique$method($p){return parent::$method($p);}";
$class_code .= "}";
#echo $class_code;
eval($class_code);
$method_info->class_name = "$unique$class_name";
$method_info->method_name = "$unique$method";
return $method_info;
}
function call_protected_user_method_array($class_name, $method, $params)
{
if(is_object($class_name))$class_name = get_class($class_name);
$unique = uniqid('Dynamic')."_";
$class_code = "class $unique$class_name extends $class_name {";
$p = array();
for ($i = 0; $i < count($params); $i++) {
$p[]='$'."P$i";
}
$p = implode(',', $p);
$class_code .= "function $unique$method($p){return parent::$method($p);}";
$class_code .= "}";
#echo $class_code;
eval($class_code);
$obj = $unique.$class_name;
$obj = new $obj();
return call_user_func_array(array($obj,$unique.$method), $params);
}
}
#requires 5.2.3
#if(!method_exists('ReflectionParameter', 'getPosition')){
#found fix! not using getPosition in restler 2.0
#}
#requires 5.3.0
#if(!defined('__DIR__')){
# avoided using it in Restler and replaced it with dirname(__FILE__)
#}

View File

@@ -0,0 +1,970 @@
<?php
/**
* CFPropertyList
* {@link http://developer.apple.com/documentation/Darwin/Reference/ManPages/man5/plist.5.html Property Lists}
* @author Rodney Rehm <rodney.rehm@medialize.de>
* @author Christian Kruse <cjk@wwwtech.de>
* @package plist
* @version $Id$
*/
/**
* Facility for reading and writing binary PropertyLists. Ported from {@link http://www.opensource.apple.com/source/CF/CF-476.15/CFBinaryPList.c CFBinaryPList.c}.
* @author Rodney Rehm <rodney.rehm@medialize.de>
* @author Christian Kruse <cjk@wwwtech.de>
* @package plist
* @example example-read-02.php Read a Binary PropertyList
* @example example-read-03.php Read a PropertyList without knowing the type
*/
abstract class CFBinaryPropertyList {
/**
* Content of the plist (unparsed string)
* @var string
*/
protected $content = NULL;
/**
* position in the (unparsed) string
* @var integer
*/
protected $pos = 0;
/**
* Table containing uniqued objects
* @var array
*/
protected $uniqueTable = Array();
/**
* Number of objects in file
* @var integer
*/
protected $countObjects = 0;
/**
* The length of all strings in the file (byte length, not character length)
* @var integer
*/
protected $stringSize = 0;
/**
* The length of all ints in file (byte length)
* @var integer
*/
protected $intSize = 0;
/**
* The length of misc objects (i.e. not integer and not string) in file
* @var integer
*/
protected $miscSize = 0;
/**
* Number of object references in file (needed to calculate reference byte length)
* @var integer
*/
protected $objectRefs = 0;
/**
* Number of objects written during save phase; needed to calculate the size of the object table
* @var integer
*/
protected $writtenObjectCount = 0;
/**
* Table containing all objects in the file
*/
protected $objectTable = Array();
/**
* The size of object references
*/
protected $objectRefSize = 0;
/**
* The „offsets” (i.e. the different entries) in the file
*/
protected $offsets = Array();
/**
* Read a „null type” (filler byte, true, false, 0 byte)
* @param $length The byte itself
* @return the byte value (e.g. CFBoolean(true), CFBoolean(false), 0 or 15)
* @throws PListException on encountering an unknown null type
*/
protected function readBinaryNullType($length) {
switch($length) {
case 0: return 0; // null type
case 8: return new CFBoolean(false);
case 9: return new CFBoolean(true);
case 15: return 15; // fill type
}
throw new PListException("unknown null type: $length");
}
/**
* Create an 64 bit integer using bcmath or gmp
* @param int $hi The higher word
* @param int $lo The lower word
* @return mixed The integer (as int if possible, as string if not possible)
* @throws PListException if neither gmp nor bc available
*/
protected static function make64Int($hi,$lo) {
// on x64, we can just use int
if(PHP_INT_SIZE > 4) return (((int)$hi)<<32) | ((int)$lo);
// lower word has to be unsigned since we don't use bitwise or, we use bcadd/gmp_add
$lo = sprintf("%u", $lo);
// use GMP or bcmath if possible
if(function_exists("gmp_mul")) return gmp_strval(gmp_add(gmp_mul($hi, "4294967296"), $lo));
if(function_exists("bcmul")) return bcadd(bcmul($hi,"4294967296"), $lo);
if(class_exists('Math_BigInteger')) {
$bi = new Math_BigInteger($hi);
return $bi->multiply("4294967296")->add($lo)->toString();
}
throw new PListException("either gmp or bc has to be installed, or the Math_BigInteger has to be available!");
}
/**
* Read an integer value
* @param integer $length The length (in bytes) of the integer value, coded as „set bit $length to 1”
* @return CFNumber The integer value
* @throws PListException if integer val is invalid
* @throws IOException if read error occurs
* @uses make64Int() to overcome PHP's big integer problems
*/
protected function readBinaryInt($length) {
if($length > 3) throw new PListException("Integer greater than 8 bytes: $length");
$nbytes = 1 << $length;
$val = null;
if(strlen($buff = substr($this->content, $this->pos, $nbytes)) != $nbytes) throw IOException::readError("");
$this->pos += $nbytes;
switch($length) {
case 0:
$val = unpack("C", $buff);
$val = $val[1];
break;
case 1:
$val = unpack("n", $buff);
$val = $val[1];
break;
case 2:
$val = unpack("N", $buff);
$val = $val[1];
break;
case 3:
$words = unpack("Nhighword/Nlowword",$buff);
//$val = $words['highword'] << 32 | $words['lowword'];
$val = self::make64Int($words['highword'],$words['lowword']);
break;
}
return new CFNumber($val);
}
/**
* Read a real value
* @param integer $length The length (in bytes) of the integer value, coded as „set bit $length to 1”
* @return CFNumber The real value
* @throws PListException if real val is invalid
* @throws IOException if read error occurs
*/
protected function readBinaryReal($length) {
if($length > 3) throw new PListException("Real greater than 8 bytes: $length");
$nbytes = 1 << $length;
$val = null;
if(strlen($buff = substr($this->content,$this->pos, $nbytes)) != $nbytes) throw IOException::readError("");
$this->pos += $nbytes;
switch($length) {
case 0: // 1 byte float? must be an error
case 1: // 2 byte float? must be an error
$x = $length + 1;
throw new PListException("got {$x} byte float, must be an error!");
case 2:
$val = unpack("f", strrev($buff));
$val = $val[1];
break;
case 3:
$val = unpack("d", strrev($buff));
$val = $val[1];
break;
}
return new CFNumber($val);
}
/**
* Read a date value
* @param integer $length The length (in bytes) of the integer value, coded as „set bit $length to 1”
* @return CFDate The date value
* @throws PListException if date val is invalid
* @throws IOException if read error occurs
*/
protected function readBinaryDate($length) {
if($length > 3) throw new PListException("Date greater than 8 bytes: $length");
$nbytes = 1 << $length;
$val = null;
if(strlen($buff = substr($this->content, $this->pos, $nbytes)) != $nbytes) throw IOException::readError("");
$this->pos += $nbytes;
switch($length) {
case 0: // 1 byte CFDate is an error
case 1: // 2 byte CFDate is an error
$x = $length + 1;
throw new PListException("{$x} byte CFdate, error");
case 2:
$val = unpack("f", strrev($buff));
$val = $val[1];
break;
case 3:
$val = unpack("d", strrev($buff));
$val = $val[1];
break;
}
return new CFDate($val,CFDate::TIMESTAMP_APPLE);
}
/**
* Read a data value
* @param integer $length The length (in bytes) of the integer value, coded as „set bit $length to 1”
* @return CFData The data value
* @throws IOException if read error occurs
*/
protected function readBinaryData($length) {
if($length == 0) $buff = "";
else {
$buff = substr($this->content, $this->pos, $length);
if(strlen($buff) != $length) throw IOException::readError("");
$this->pos += $length;
}
return new CFData($buff,false);
}
/**
* Read a string value, usually coded as utf8
* @param integer $length The length (in bytes) of the string value
* @return CFString The string value, utf8 encoded
* @throws IOException if read error occurs
*/
protected function readBinaryString($length) {
if($length == 0) $buff = "";
else {
if(strlen($buff = substr($this->content, $this->pos, $length)) != $length) throw IOException::readError("");
$this->pos += $length;
}
if(!isset($this->uniqueTable[$buff])) $this->uniqueTable[$buff] = true;
return new CFString($buff);
}
/**
* Convert the given string from one charset to another.
* Trying to use MBString, Iconv, Recode - in that particular order.
* @param string $string the string to convert
* @param string $fromCharset the charset the given string is currently encoded in
* @param string $toCharset the charset to convert to, defaults to UTF-8
* @return string the converted string
* @throws PListException on neither MBString, Iconv, Recode being available
*/
public static function convertCharset($string, $fromCharset, $toCharset='UTF-8') {
if(function_exists('mb_convert_encoding')) return mb_convert_encoding($string, $toCharset, $fromCharset);
if(function_exists('iconv')) return iconv($fromCharset, $toCharset, $string);
if(function_exists('recode_string')) return recode_string($fromCharset .'..'. $toCharset, $string);
throw new PListException('neither iconv nor mbstring supported. how are we supposed to work on strings here?');
}
/**
* Count characters considering character set
* Trying to use MBString, Iconv - in that particular order.
* @param string $string the string to convert
* @param string $charset the charset the given string is currently encoded in
* @return integer The number of characters in that string
* @throws PListException on neither MBString, Iconv being available
*/
public static function charsetStrlen($string,$charset="UTF-8") {
if(function_exists('mb_strlen')) return mb_strlen($string, $charset);
if(function_exists('iconv_strlen')) return iconv_strlen($string,$charset);
throw new PListException('neither iconv nor mbstring supported. how are we supposed to work on strings here?');
}
/**
* Read a unicode string value, coded as UTF-16BE
* @param integer $length The length (in bytes) of the string value
* @return CFString The string value, utf8 encoded
* @throws IOException if read error occurs
*/
protected function readBinaryUnicodeString($length) {
/* The problem is: we get the length of the string IN CHARACTERS;
since a char in UTF-16 can be 16 or 32 bit long, we don't really know
how long the string is in bytes */
if(strlen($buff = substr($this->content, $this->pos, 2*$length)) != 2*$length) throw IOException::readError("");
$this->pos += 2 * $length;
if(!isset($this->uniqueTable[$buff])) $this->uniqueTable[$buff] = true;
return new CFString(self::convertCharset($buff, "UTF-16BE", "UTF-8"));
}
/**
* Read an array value, including contained objects
* @param integer $length The number of contained objects
* @return CFArray The array value, including the objects
* @throws IOException if read error occurs
*/
protected function readBinaryArray($length) {
$ary = new CFArray();
// first: read object refs
if($length != 0) {
if(strlen($buff = substr($this->content, $this->pos, $length * $this->objectRefSize)) != $length * $this->objectRefSize) throw IOException::readError("");
$this->pos += $length * $this->objectRefSize;
$objects = unpack($this->objectRefSize == 1 ? "C*" : "n*", $buff);
// now: read objects
for($i=0;$i<$length;++$i) {
$object = $this->readBinaryObjectAt($objects[$i+1]+1,$this->objectRefSize);
$ary->add($object);
}
}
return $ary;
}
/**
* Read a dictionary value, including contained objects
* @param integer $length The number of contained objects
* @return CFDictionary The dictionary value, including the objects
* @throws IOException if read error occurs
*/
protected function readBinaryDict($length) {
$dict = new CFDictionary();
// first: read keys
if($length != 0) {
if(strlen($buff = substr($this->content, $this->pos, $length * $this->objectRefSize)) != $length * $this->objectRefSize) throw IOException::readError("");
$this->pos += $length * $this->objectRefSize;
$keys = unpack(($this->objectRefSize == 1 ? "C*" : "n*"), $buff);
// second: read object refs
if(strlen($buff = substr($this->content, $this->pos, $length * $this->objectRefSize)) != $length * $this->objectRefSize) throw IOException::readError("");
$this->pos += $length * $this->objectRefSize;
$objects = unpack(($this->objectRefSize == 1 ? "C*" : "n*"), $buff);
// read real keys and objects
for($i=0;$i<$length;++$i) {
$key = $this->readBinaryObjectAt($keys[$i+1]+1);
$object = $this->readBinaryObjectAt($objects[$i+1]+1);
$dict->add($key->getValue(),$object);
}
}
return $dict;
}
/**
* Read an object type byte, decode it and delegate to the correct reader function
* @return mixed The value of the delegate reader, so any of the CFType subclasses
* @throws IOException if read error occurs
*/
function readBinaryObject() {
// first: read the marker byte
if(strlen($buff = substr($this->content,$this->pos,1)) != 1) throw IOException::readError("");
$this->pos++;
$object_length = unpack("C*", $buff);
$object_length = $object_length[1] & 0xF;
$buff = unpack("H*", $buff);
$buff = $buff[1];
$object_type = substr($buff, 0, 1);
if($object_type != "0" && $object_length == 15) {
$object_length = $this->readBinaryObject($this->objectRefSize);
$object_length = $object_length->getValue();
}
$retval = null;
switch($object_type) {
case '0': // null, false, true, fillbyte
$retval = $this->readBinaryNullType($object_length);
break;
case '1': // integer
$retval = $this->readBinaryInt($object_length);
break;
case '2': // real
$retval = $this->readBinaryReal($object_length);
break;
case '3': // date
$retval = $this->readBinaryDate($object_length);
break;
case '4': // data
$retval = $this->readBinaryData($object_length);
break;
case '5': // byte string, usually utf8 encoded
$retval = $this->readBinaryString($object_length);
break;
case '6': // unicode string (utf16be)
$retval = $this->readBinaryUnicodeString($object_length);
break;
case 'a': // array
$retval = $this->readBinaryArray($object_length);
break;
case 'd': // dictionary
$retval = $this->readBinaryDict($object_length);
break;
}
return $retval;
}
/**
* Read an object type byte at position $pos, decode it and delegate to the correct reader function
* @param integer $pos The table position in the offsets table
* @return mixed The value of the delegate reader, so any of the CFType subclasses
*/
function readBinaryObjectAt($pos) {
$this->pos = $this->offsets[$pos];
return $this->readBinaryObject();
}
/**
* Parse a binary plist string
* @return void
* @throws IOException if read error occurs
*/
public function parseBinaryString() {
$this->uniqueTable = Array();
$this->countObjects = 0;
$this->stringSize = 0;
$this->intSize = 0;
$this->miscSize = 0;
$this->objectRefs = 0;
$this->writtenObjectCount = 0;
$this->objectTable = Array();
$this->objectRefSize = 0;
$this->offsets = Array();
// first, we read the trailer: 32 byte from the end
$buff = substr($this->content,-32);
$infos = unpack("x6/Coffset_size/Cobject_ref_size/x4/Nnumber_of_objects/x4/Ntop_object/x4/Ntable_offset",$buff);
// after that, get the offset table
$coded_offset_table = substr($this->content,$infos['table_offset'],$infos['number_of_objects'] * $infos['offset_size']);
if(strlen($coded_offset_table) != $infos['number_of_objects'] * $infos['offset_size']) throw IOException::readError("");
$this->countObjects = $infos['number_of_objects'];
// decode offset table
$formats = Array("","C*","n*",NULL,"N*");
if($infos['offset_size'] == 3) { # since PHP does not support parenthesis in pack/unpack expressions,
# "(H6)*" does not work and we have to work round this by repeating the
# expression as often as it fits in the string
$this->offsets = array(NULL);
while($coded_offset_table) {
$str = unpack("H6",$coded_offset_table);
$this->offsets[] = hexdec($str[1]);
$coded_offset_table = substr($coded_offset_table,3);
}
}
else $this->offsets = unpack($formats[$infos['offset_size']],$coded_offset_table);
$this->uniqueTable = Array();
$this->objectRefSize = $infos['object_ref_size'];
$top = $this->readBinaryObjectAt($infos['top_object']+1);
$this->add($top);
}
/**
* Read a binary plist stream
* @param resource $stream The stream to read
* @return void
* @throws IOException if read error occurs
*/
function readBinaryStream($stream) {
$str = stream_get_contents($stream);
$this->parseBinary($str);
}
/**
* parse a binary plist string
* @param string $content The stream to read, defaults to {@link $this->content}
* @return void
* @throws IOException if read error occurs
*/
function parseBinary($content=NULL) {
if($content !== NULL) $this->content = $content;
$this->pos = 0;
$this->parseBinaryString();
}
/**
* Read a binary plist file
* @param string $file The file to read
* @return void
* @throws IOException if read error occurs
*/
function readBinary($file) {
if(!($fd = fopen($file,"rb"))) throw new IOException("Could not open file {$file}!");
$this->readBinaryStream($fd);
fclose($fd);
}
/**
* calculate the bytes needed for a size integer value
* @param integer $int The integer value to calculate
* @return integer The number of bytes needed
*/
public static function bytesSizeInt($int) {
$nbytes = 0;
if($int > 0xE) $nbytes += 2; // 2 size-bytes
if($int > 0xFF) $nbytes += 1; // 3 size-bytes
if($int > 0xFFFF) $nbytes += 2; // 5 size-bytes
return $nbytes;
}
/**
* Calculate the byte needed for a „normal” integer value
* @param integer $int The integer value
* @return integer The number of bytes needed + 1 (because of the „marker byte”)
*/
public static function bytesInt($int) {
$nbytes = 1;
if($int > 0xFF) $nbytes += 1; // 2 byte integer
if($int > 0xFFFF) $nbytes += 2; // 4 byte integer
if($int > 0xFFFFFFFF) $nbytes += 4; // 8 byte integer
if($int < 0) $nbytes += 7; // 8 byte integer (since it is signed)
return $nbytes + 1; // one „marker” byte
}
/**
* „pack” a value (i.e. write the binary representation as big endian to a string) with the specified size
* @param integer $nbytes The number of bytes to pack
* @param integer $int the integer value to pack
* @return string The packed value as string
*/
public static function packItWithSize($nbytes,$int) {
$formats = Array("C", "n", "N", "N");
$format = $formats[$nbytes-1];
$ret = '';
if($nbytes == 3) return substr(pack($format, $int), -3);
return pack($format, $int);
}
/**
* Calculate the bytes needed to save the number of objects
* @param integer $count_objects The number of objects
* @return integer The number of bytes
*/
public static function bytesNeeded($count_objects) {
$nbytes = 0;
while($count_objects >= 1) {
$nbytes++;
$count_objects /= 256;
}
return $nbytes;
}
/**
* Code an integer to byte representation
* @param integer $int The integer value
* @return string The packed byte value
*/
public static function intBytes($int) {
$intbytes = "";
if($int > 0xFFFF) $intbytes = "\x12".pack("N", $int); // 4 byte integer
elseif($int > 0xFF) $intbytes = "\x11".pack("n", $int); // 2 byte integer
else $intbytes = "\x10".pack("C", $int); // 8 byte integer
return $intbytes;
}
/**
* Code an type byte, consisting of the type marker and the length of the type
* @param string $type The type byte value (i.e. "d" for dictionaries)
* @param integer $type_len The length of the type
* @return string The packed type byte value
*/
public static function typeBytes($type,$type_len) {
$optional_int = "";
if($type_len < 15) $type .= sprintf("%x", $type_len);
else {
$type .= "f";
$optional_int = self::intBytes($type_len);
}
return pack("H*", $type).$optional_int;
}
/**
* Count number of objects and create a unique table for strings
* @param $value The value to count and unique
* @return void
*/
protected function uniqueAndCountValues($value) {
// no uniquing for other types than CFString and CFData
if($value instanceof CFNumber) {
$val = $value->getValue();
if(intval($val) == $val && !is_float($val) && strpos($val,'.') === false) $this->intSize += self::bytesInt($val);
else $this->miscSize += 9; // 9 bytes (8 + marker byte) for real
$this->countObjects++;
return;
}
elseif($value instanceof CFDate) {
$this->miscSize += 9; // since date in plist is real, we need 9 byte (8 + marker byte)
$this->countObjects++;
return;
}
elseif($value instanceof CFBoolean) {
$this->countObjects++;
$this->miscSize += 1;
return;
}
elseif($value instanceof CFArray) {
$cnt = 0;
foreach($value as $v) {
++$cnt;
$this->uniqueAndCountValues($v);
$this->objectRefs++; // each array member is a ref
}
$this->countObjects++;
$this->intSize += self::bytesSizeInt($cnt);
$this->miscSize++; // marker byte for array
return;
}
elseif($value instanceof CFDictionary) {
$cnt = 0;
foreach($value as $k => $v) {
++$cnt;
if(!isset($this->uniqueTable[$k])) {
$this->uniqueTable[$k] = 0;
$len = self::binaryStrlen($k);
$this->stringSize += $len + 1;
$this->intSize += self::bytesSizeInt(self::charsetStrlen($k,'UTF-8'));
}
$this->objectRefs += 2; // both, key and value, are refs
$this->uniqueTable[$k]++;
$this->uniqueAndCountValues($v);
}
$this->countObjects++;
$this->miscSize++; // marker byte for dict
$this->intSize += self::bytesSizeInt($cnt);
return;
}
elseif($value instanceOf CFData) {
$val = $value->getValue();
$len = strlen($val);
$this->intSize += self::bytesSizeInt($len);
$this->miscSize += $len + 1;
$this->countObjects++;
return;
}
else $val = $value->getValue();
if(!isset($this->uniqueTable[$val])) {
$this->uniqueTable[$val] = 0;
$len = self::binaryStrlen($val);
$this->stringSize += $len + 1;
$this->intSize += self::bytesSizeInt(self::charsetStrlen($val,'UTF-8'));
}
$this->uniqueTable[$val]++;
}
/**
* Convert CFPropertyList to binary format; since we have to count our objects we simply unique CFDictionary and CFArray
* @return string The binary plist content
*/
public function toBinary() {
$this->uniqueTable = Array();
$this->countObjects = 0;
$this->stringSize = 0;
$this->intSize = 0;
$this->miscSize = 0;
$this->objectRefs = 0;
$this->writtenObjectCount = 0;
$this->objectTable = Array();
$this->objectRefSize = 0;
$this->offsets = Array();
$binary_str = "bplist00";
$value = $this->getValue(true);
$this->uniqueAndCountValues($value);
$this->countObjects += count($this->uniqueTable);
$this->objectRefSize = self::bytesNeeded($this->countObjects);
$file_size = $this->stringSize + $this->intSize + $this->miscSize + $this->objectRefs * $this->objectRefSize + 40;
$offset_size = self::bytesNeeded($file_size);
$table_offset = $file_size - 32;
$this->objectTable = Array();
$this->writtenObjectCount = 0;
$this->uniqueTable = Array(); // we needed it to calculate several values
$value->toBinary($this);
$object_offset = 8;
$offsets = Array();
for($i=0;$i<count($this->objectTable);++$i) {
$binary_str .= $this->objectTable[$i];
$offsets[$i] = $object_offset;
$object_offset += strlen($this->objectTable[$i]);
}
for($i=0;$i<count($offsets);++$i) {
$binary_str .= self::packItWithSize($offset_size, $offsets[$i]);
}
$binary_str .= pack("x6CC", $offset_size, $this->objectRefSize);
$binary_str .= pack("x4N", $this->countObjects);
$binary_str .= pack("x4N", 0);
$binary_str .= pack("x4N", $table_offset);
return $binary_str;
}
/**
* Counts the number of bytes the string will have when coded; utf-16be if non-ascii characters are present.
* @param string $val The string value
* @return integer The length of the coded string in bytes
*/
protected static function binaryStrlen($val) {
for($i=0;$i<strlen($val);++$i) {
if(ord($val{$i}) >= 128) {
$val = self::convertCharset($val, 'UTF-8', 'UTF-16BE');
return strlen($val);
}
}
return strlen($val);
}
/**
* Uniques and transforms a string value to binary format and adds it to the object table
* @param string $val The string value
* @return integer The position in the object table
*/
public function stringToBinary($val) {
$saved_object_count = -1;
if(!isset($this->uniqueTable[$val])) {
$saved_object_count = $this->writtenObjectCount++;
$this->uniqueTable[$val] = $saved_object_count;
$utf16 = false;
for($i=0;$i<strlen($val);++$i) {
if(ord($val{$i}) >= 128) {
$utf16 = true;
break;
}
}
if($utf16) {
$bdata = self::typeBytes("6", mb_strlen($val,'UTF-8')); // 6 is 0110, unicode string (utf16be)
$val = self::convertCharset($val, 'UTF-8', 'UTF-16BE');
$this->objectTable[$saved_object_count] = $bdata.$val;
}
else {
$bdata = self::typeBytes("5", strlen($val)); // 5 is 0101 which is an ASCII string (seems to be ASCII encoded)
$this->objectTable[$saved_object_count] = $bdata.$val;
}
}
else $saved_object_count = $this->uniqueTable[$val];
return $saved_object_count;
}
/**
* Codes an integer to binary format
* @param integer $value The integer value
* @return string the coded integer
*/
protected function intToBinary($value) {
$nbytes = 0;
if($value > 0xFF) $nbytes = 1; // 1 byte integer
if($value > 0xFFFF) $nbytes += 1; // 4 byte integer
if($value > 0xFFFFFFFF) $nbytes += 1; // 8 byte integer
if($value < 0) $nbytes = 3; // 8 byte integer, since signed
$bdata = self::typeBytes("1", $nbytes); // 1 is 0001, type indicator for integer
$buff = "";
if($nbytes < 3) {
if($nbytes == 0) $fmt = "C";
elseif($nbytes == 1) $fmt = "n";
else $fmt = "N";
$buff = pack($fmt, $value);
}
else {
if(PHP_INT_SIZE > 4) {
// 64 bit signed integer; we need the higher and the lower 32 bit of the value
$high_word = $value >> 32;
$low_word = $value & 0xFFFFFFFF;
}
else {
// since PHP can only handle 32bit signed, we can only get 32bit signed values at this point - values above 0x7FFFFFFF are
// floats. So we ignore the existance of 64bit on non-64bit-machines
if($value < 0) $high_word = 0xFFFFFFFF;
else $high_word = 0;
$low_word = $value;
}
$buff = pack("N", $high_word).pack("N", $low_word);
}
return $bdata.$buff;
}
/**
* Codes a real value to binary format
* @param float $val The real value
* @return string The coded real
*/
protected function realToBinary($val) {
$bdata = self::typeBytes("2", 3); // 2 is 0010, type indicator for reals
return $bdata.strrev(pack("d", (float)$val));
}
/**
* Converts a numeric value to binary and adds it to the object table
* @param numeric $value The numeric value
* @return integer The position in the object table
*/
public function numToBinary($value) {
$saved_object_count = $this->writtenObjectCount++;
$val = "";
if(intval($value) == $value && !is_float($value) && strpos($value,'.') === false) $val = $this->intToBinary($value);
else $val = $this->realToBinary($value);
$this->objectTable[$saved_object_count] = $val;
return $saved_object_count;
}
/**
* Convert date value (apple format) to binary and adds it to the object table
* @param integer $value The date value
* @return integer The position of the coded value in the object table
*/
public function dateToBinary($val) {
$saved_object_count = $this->writtenObjectCount++;
$hour = gmdate("H",$val);
$min = gmdate("i",$val);
$sec = gmdate("s",$val);
$mday = gmdate("j",$val);
$mon = gmdate("n",$val);
$year = gmdate("Y",$val);
$val = gmmktime($hour,$min,$sec,$mon,$mday,$year) - CFDate::DATE_DIFF_APPLE_UNIX; // CFDate is a real, number of seconds since 01/01/2001 00:00:00 GMT
$bdata = self::typeBytes("3", 3); // 3 is 0011, type indicator for date
$this->objectTable[$saved_object_count] = $bdata.strrev(pack("d", $val));
return $saved_object_count;
}
/**
* Convert a bool value to binary and add it to the object table
* @param bool $val The boolean value
* @return integer The position in the object table
*/
public function boolToBinary($val) {
$saved_object_count = $this->writtenObjectCount++;
$this->objectTable[$saved_object_count] = $val ? "\x9" : "\x8"; // 0x9 is 1001, type indicator for true; 0x8 is 1000, type indicator for false
return $saved_object_count;
}
/**
* Convert data value to binary format and add it to the object table
* @param string $val The data value
* @return integer The position in the object table
*/
public function dataToBinary($val) {
$saved_object_count = $this->writtenObjectCount++;
$bdata = self::typeBytes("4", strlen($val)); // a is 1000, type indicator for data
$this->objectTable[$saved_object_count] = $bdata.$val;
return $saved_object_count;
}
/**
* Convert array to binary format and add it to the object table
* @param CFArray $val The array to convert
* @return integer The position in the object table
*/
public function arrayToBinary($val) {
$saved_object_count = $this->writtenObjectCount++;
$bdata = self::typeBytes("a", count($val->getValue())); // a is 1010, type indicator for arrays
foreach($val as $v) {
$bval = $v->toBinary($this);
$bdata .= self::packItWithSize($this->objectRefSize, $bval);
}
$this->objectTable[$saved_object_count] = $bdata;
return $saved_object_count;
}
/**
* Convert dictionary to binary format and add it to the object table
* @param CFDictionary $val The dict to convert
* @return integer The position in the object table
*/
public function dictToBinary($val) {
$saved_object_count = $this->writtenObjectCount++;
$bdata = self::typeBytes("d", count($val->getValue())); // d=1101, type indicator for dictionary
foreach($val as $k => $v) {
$str = new CFString($k);
$key = $str->toBinary($this);
$bdata .= self::packItWithSize($this->objectRefSize, $key);
}
foreach($val as $k => $v) {
$bval = $v->toBinary($this);
$bdata .= self::packItWithSize($this->objectRefSize, $bval);
}
$this->objectTable[$saved_object_count] = $bdata;
return $saved_object_count;
}
}
?>

View File

@@ -0,0 +1,586 @@
<?php
/**
* CFPropertyList
* {@link http://developer.apple.com/documentation/Darwin/Reference/ManPages/man5/plist.5.html Property Lists}
* @author Rodney Rehm <rodney.rehm@medialize.de>
* @author Christian Kruse <cjk@wwwtech.de>
* @package plist
* @version $Id$
* @example example-read-01.php Read an XML PropertyList
* @example example-read-02.php Read a Binary PropertyList
* @example example-read-03.php Read a PropertyList without knowing the type
* @example example-create-01.php Using the CFPropertyList API
* @example example-create-02.php Using {@link CFTypeDetector}
* @example example-create-03.php Using {@link CFTypeDetector} with {@link CFDate} and {@link CFData}
* @example example-modify-01.php Read, modify and save a PropertyList
*/
/**
* Require IOException, PListException, CFType and CFBinaryPropertyList
*/
require_once('IOException.php');
require_once('PListException.php');
require_once('CFType.php');
require_once('CFBinaryPropertyList.php');
require_once('CFTypeDetector.php');
/**
* Property List
* Interface for handling reading, editing and saving Property Lists as defined by Apple.
* @author Rodney Rehm <rodney.rehm@medialize.de>
* @author Christian Kruse <cjk@wwwtech.de>
* @package plist
* @example example-read-01.php Read an XML PropertyList
* @example example-read-02.php Read a Binary PropertyList
* @example example-read-03.php Read a PropertyList without knowing the type
* @example example-create-01.php Using the CFPropertyList API
* @example example-create-02.php Using {@link CFTypeDetector}
* @example example-create-03.php Using {@link CFTypeDetector} with {@link CFDate} and {@link CFData}
* @example example-create-04.php Using and extended {@link CFTypeDetector}
*/
class CFPropertyList extends CFBinaryPropertyList implements Iterator {
/**
* Format constant for binary format
* @var integer
*/
const FORMAT_BINARY = 1;
/**
* Format constant for xml format
* @var integer
*/
const FORMAT_XML = 2;
/**
* Format constant for automatic format recognizing
* @var integer
*/
const FORMAT_AUTO = 0;
/**
* Path of PropertyList
* @var string
*/
protected $file = null;
/**
* Path of PropertyList
* @var integer
*/
protected $format = null;
/**
* CFType nodes
* @var array
*/
protected $value = array();
/**
* Position of iterator {@link http://php.net/manual/en/class.iterator.php}
* @var integer
*/
protected $iteratorPosition = 0;
/**
* List of Keys for numerical iterator access {@link http://php.net/manual/en/class.iterator.php}
* @var array
*/
protected $iteratorKeys = null;
/**
* List of NodeNames to ClassNames for resolving plist-files
* @var array
*/
protected static $types = array(
'string' => 'CFString',
'real' => 'CFNumber',
'integer' => 'CFNumber',
'date' => 'CFDate',
'true' => 'CFBoolean',
'false' => 'CFBoolean',
'data' => 'CFData',
'array' => 'CFArray',
'dict' => 'CFDictionary'
);
/**
* Create new CFPropertyList.
* If a path to a PropertyList is specified, it is loaded automatically.
* @param string $file Path of PropertyList
* @param integer $format he format of the property list, see {@link FORMAT_XML}, {@link FORMAT_BINARY} and {@link FORMAT_AUTO}, defaults to {@link FORMAT_AUTO}
* @throws IOException if file could not be read by {@link load()}
* @uses $file for storing the current file, if specified
* @uses load() for loading the plist-file
*/
public function __construct($file=null,$format=self::FORMAT_AUTO) {
$this->file = $file;
$this->format = $format;
if($this->file) $this->load();
}
/**
* Load an XML PropertyList.
* @param string $file Path of PropertyList, defaults to {@link $file}
* @return void
* @throws IOException if file could not be read
* @throws DOMException if XML-file could not be read properly
* @uses load() to actually load the file
*/
public function loadXML($file=null) {
$this->load($file,CFPropertyList::FORMAT_XML);
}
/**
* Load an XML PropertyList.
* @param resource $stream A stream containing the xml document.
* @return void
* @throws IOException if stream could not be read
* @throws DOMException if XML-stream could not be read properly
*/
public function loadXMLStream($stream) {
if(($contents = stream_get_contents($stream)) === FALSE) throw IOException::notReadable('<stream>');
$this->parse($content,CFPropertyList::FORMAT_XML);
}
/**
* Load an binary PropertyList.
* @param string $file Path of PropertyList, defaults to {@link $file}
* @return void
* @throws IOException if file could not be read
* @throws PListException if binary plist-file could not be read properly
* @uses load() to actually load the file
*/
public function loadBinary($file=null) {
$this->load($file,CFPropertyList::FORMAT_BINARY);
}
/**
* Load an binary PropertyList.
* @param stream $stream Stream containing the PropertyList
* @return void
* @throws IOException if file could not be read
* @throws PListException if binary plist-file could not be read properly
* @uses parse() to actually load the file
*/
public function loadBinaryStream($stream) {
if(($contents = stream_get_contents($stream)) === FALSE) throw IOException::notReadable('<stream>');
$this->parse($content,CFPropertyList::FORMAT_BINARY);
}
/**
* Load a plist file.
* Load and import a plist file.
* @param string $file Path of PropertyList, defaults to {@link $file}
* @param integer $format The format of the property list, see {@link FORMAT_XML}, {@link FORMAT_BINARY} and {@link FORMAT_AUTO}, defaults to {@link $format}
* @return void
* @throws PListException if file format version is not 00
* @throws IOException if file could not be read
* @throws DOMException if plist file could not be parsed properly
* @uses $file if argument $file was not specified
* @uses $value reset to empty array
* @uses import() for importing the values
*/
public function load($file=null,$format=null) {
$file = $file ? $file : $this->file;
$format = $format !== null ? $format : $this->format;
$this->value = array();
if(!is_readable($file)) throw IOException::notReadable($file);
switch($format) {
case CFPropertyList::FORMAT_BINARY:
$this->readBinary($file);
break;
case CFPropertyList::FORMAT_AUTO: // what we now do is ugly, but neccessary to recognize the file format
$fd = fopen($file,"rb");
if(($magic_number = fread($fd,8)) === false) throw IOException::notReadable($file);
fclose($fd);
$filetype = substr($magic_number,0,6);
$version = substr($magic_number,-2);
if($filetype == "bplist") {
if($version != "00") throw new PListException("Wrong file format version! Expected 00, got $version!");
$this->readBinary($file);
break;
}
// else: xml format, break not neccessary
case CFPropertyList::FORMAT_XML:
$doc = new DOMDocument();
if(!$doc->load($file)) throw new DOMException();
$this->import($doc->documentElement, $this);
break;
}
}
/**
* Parse a plist string.
* Parse and import a plist string.
* @param string $str String containing the PropertyList, defaults to {@link $content}
* @param integer $format The format of the property list, see {@link FORMAT_XML}, {@link FORMAT_BINARY} and {@link FORMAT_AUTO}, defaults to {@link $format}
* @return void
* @throws PListException if file format version is not 00
* @throws IOException if file could not be read
* @throws DOMException if plist file could not be parsed properly
* @uses $content if argument $str was not specified
* @uses $value reset to empty array
* @uses import() for importing the values
*/
public function parse($str=NULL,$format=NULL) {
$format = $format !== null ? $format : $this->format;
$str = $str !== null ? $str : $this->content;
$this->value = array();
switch($format) {
case CFPropertyList::FORMAT_BINARY:
$this->parseBinary($str);
break;
case CFPropertyList::FORMAT_AUTO: // what we now do is ugly, but neccessary to recognize the file format
if(($magic_number = substr($str,0,8)) === false) throw IOException::notReadable("<string>");
$filetype = substr($magic_number,0,6);
$version = substr($magic_number,-2);
if($filetype == "bplist") {
if($version != "00") throw new PListException("Wrong file format version! Expected 00, got $version!");
$this->parseBinary($str);
break;
}
// else: xml format, break not neccessary
case CFPropertyList::FORMAT_XML:
$doc = new DOMDocument();
if(!$doc->loadXML($str)) throw new DOMException();
$this->import($doc->documentElement, $this);
break;
}
}
/**
* Convert a DOMNode into a CFType.
* @param DOMNode $node Node to import children of
* @param CFDictionary|CFArray|CFPropertyList $parent
* @return void
*/
protected function import(DOMNode $node, $parent) {
// abort if there are no children
if(!$node->childNodes->length) return;
foreach($node->childNodes as $n) {
// skip if we can't handle the element
if(!isset(self::$types[$n->nodeName])) continue;
$class = self::$types[$n->nodeName];
$key = null;
// find previous <key> if possible
$ps = $n->previousSibling;
while($ps && $ps->nodeName == '#text' && $ps->previousSibling) $ps = $ps->previousSibling;
// read <key> if possible
if($ps && $ps->nodeName == 'key') $key = $ps->firstChild->nodeValue;
switch($n->nodeName) {
case 'date':
$value = new $class(CFDate::dateValue($n->nodeValue));
break;
case 'data':
$value = new $class($n->nodeValue,true);
break;
case 'string':
$value = new $class($n->nodeValue);
break;
case 'real':
case 'integer':
$value = new $class($n->nodeName == 'real' ? floatval($n->nodeValue) : intval($n->nodeValue));
break;
case 'true':
case 'false':
$value = new $class($n->nodeName == 'true');
break;
case 'array':
case 'dict':
$value = new $class();
$this->import($n, $value);
break;
}
// Dictionaries need a key
if($parent instanceof CFDictionary) $parent->add($key, $value);
// others don't
else $parent->add($value);
}
}
/**
* Convert CFPropertyList to XML and save to file.
* @param string $file Path of PropertyList, defaults to {@link $file}
* @return void
* @throws IOException if file could not be read
* @uses $file if $file was not specified
*/
public function saveXML($file) {
$this->save($file,CFPropertyList::FORMAT_XML);
}
/**
* Convert CFPropertyList to binary format (bplist00) and save to file.
* @param string $file Path of PropertyList, defaults to {@link $file}
* @return void
* @throws IOException if file could not be read
* @uses $file if $file was not specified
*/
public function saveBinary($file) {
$this->save($file,CFPropertyList::FORMAT_BINARY);
}
/**
* Convert CFPropertyList to XML or binary and save to file.
* @param string $file Path of PropertyList, defaults to {@link $file}
* @param string $format Format of PropertyList, defaults to {@link $format}
* @return void
* @throws IOException if file could not be read
* @throws PListException if evaluated $format is neither {@link FORMAT_XML} nor {@link FORMAL_BINARY}
* @uses $file if $file was not specified
* @uses $format if $format was not specified
*/
public function save($file=null,$format=null) {
$file = $file ? $file : $this->file;
$format = $format ? $format : $this->format;
if( !in_array( $format, array( self::FORMAT_BINARY, self::FORMAT_XML ) ) )
throw new PListException( "format {$format} is not supported, use CFPropertyList::FORMAT_BINARY or CFPropertyList::FORMAT_XML" );
if(!file_exists($file)) {
// dirname("file.xml") == "" and is treated as the current working directory
if(!is_writable(dirname($file))) throw IOException::notWritable($file);
}
else if(!is_writable($file)) throw IOException::notWritable($file);
$content = $format == self::FORMAT_BINARY ? $this->toBinary() : $this->toXML();
$fh = fopen($file, 'wb');
fwrite($fh,$content);
fclose($fh);
}
/**
* Convert CFPropertyList to XML
* @param bool $formatted Print plist formatted (i.e. with newlines and whitespace indention) if true; defaults to false
* @return string The XML content
*/
public function toXML($formatted=false) {
$domimpl = new DOMImplementation();
// <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
$dtd = $domimpl->createDocumentType('plist', '-//Apple Computer//DTD PLIST 1.0//EN', 'http://www.apple.com/DTDs/PropertyList-1.0.dtd');
$doc = $domimpl->createDocument(null, "plist", $dtd);
$doc->encoding = "UTF-8";
// format output
if($formatted) {
$doc->formatOutput = true;
$doc->preserveWhiteSpace = true;
}
// get documentElement and set attribs
$plist = $doc->documentElement;
$plist->setAttribute('version', '1.0');
// add PropertyList's children
$plist->appendChild($this->getValue(true)->toXML($doc));
return $doc->saveXML();
}
/************************************************************************************************
* M A N I P U L A T I O N
************************************************************************************************/
/**
* Add CFType to collection.
* @param CFType $value CFType to add to collection
* @return void
* @uses $value for adding $value
*/
public function add(CFType $value=null) {
// anything but CFType is null, null is an empty string - sad but true
if( !$value )
$value = new CFString();
$this->value[] = $value;
}
/**
* Get CFType from collection.
* @param integer $key Key of CFType to retrieve from collection
* @return CFType CFType found at $key, null else
* @uses $value for retrieving CFType of $key
*/
public function get($key) {
if(isset($this->value[$key])) return $this->value[$key];
return null;
}
/**
* Generic getter (magic)
*
* @param integer $key Key of CFType to retrieve from collection
* @return CFType CFType found at $key, null else
* @author Sean Coates <sean@php.net>
* @link http://php.net/oop5.overloading
*/
public function __get($key) {
return $this->get($key);
}
/**
* Remove CFType from collection.
* @param integer $key Key of CFType to removes from collection
* @return CFType removed CFType, null else
* @uses $value for removing CFType of $key
*/
public function del($key) {
if(isset($this->value[$key])) {
$t = $this->value[$key];
unset($this->value[$key]);
return $t;
}
return null;
}
/**
* Empty the collection
* @return array the removed CFTypes
* @uses $value for removing CFType of $key
*/
public function purge() {
$t = $this->value;
$this->value = array();
return $t;
}
/**
* Get first (and only) child, or complete collection.
* @param string $cftype if set to true returned value will be CFArray instead of an array in case of a collection
* @return CFType|array CFType or list of CFTypes known to the PropertyList
* @uses $value for retrieving CFTypes
*/
public function getValue($cftype=false) {
if(count($this->value) === 1) {
$t = array_values( $this->value );
return $t[0];
}
if($cftype) {
$t = new CFArray();
foreach( $this->value as $value ) {
if( $value instanceof CFType ) $t->add($value);
}
return $t;
}
return $this->value;
}
/**
* Create CFType-structure from guessing the data-types.
* The functionality has been moved to the more flexible {@link CFTypeDetector} facility.
* @param mixed $value Value to convert to CFType
* @param boolean $autoDictionary if true {@link CFArray}-detection is bypassed and arrays will be returned as {@link CFDictionary}.
* @return CFType CFType based on guessed type
* @uses CFTypeDetector for actual type detection
* @deprecated
*/
public static function guess($value, $autoDictionary=false) {
static $t = null;
if( $t === null )
$t = new CFTypeDetector( $autoDictionary );
return $t->toCFType( $value );
}
/************************************************************************************************
* S E R I A L I Z I N G
************************************************************************************************/
/**
* Get PropertyList as array.
* @return mixed primitive value of first (and only) CFType, or array of primitive values of collection
* @uses $value for retrieving CFTypes
*/
public function toArray() {
$a = array();
foreach($this->value as $value) $a[] = $value->toArray();
if(count($a) === 1) return $a[0];
return $a;
}
/************************************************************************************************
* I T E R A T O R I N T E R F A C E
************************************************************************************************/
/**
* Rewind {@link $iteratorPosition} to first position (being 0)
* @link http://php.net/manual/en/iterator.rewind.php
* @return void
* @uses $iteratorPosition set to 0
* @uses $iteratorKeys store keys of {@link $value}
*/
public function rewind() {
$this->iteratorPosition = 0;
$this->iteratorKeys = array_keys($this->value);
}
/**
* Get Iterator's current {@link CFType} identified by {@link $iteratorPosition}
* @link http://php.net/manual/en/iterator.current.php
* @return CFType current Item
* @uses $iteratorPosition identify current key
* @uses $iteratorKeys identify current value
*/
public function current() {
return $this->value[$this->iteratorKeys[$this->iteratorPosition]];
}
/**
* Get Iterator's current key identified by {@link $iteratorPosition}
* @link http://php.net/manual/en/iterator.key.php
* @return string key of the current Item
* @uses $iteratorPosition identify current key
* @uses $iteratorKeys identify current value
*/
public function key() {
return $this->iteratorKeys[$this->iteratorPosition];
}
/**
* Increment {@link $iteratorPosition} to address next {@see CFType}
* @link http://php.net/manual/en/iterator.next.php
* @return void
* @uses $iteratorPosition increment by 1
*/
public function next() {
$this->iteratorPosition++;
}
/**
* Test if {@link $iteratorPosition} addresses a valid element of {@link $value}
* @link http://php.net/manual/en/iterator.valid.php
* @return boolean true if current position is valid, false else
* @uses $iteratorPosition test if within {@link $iteratorKeys}
* @uses $iteratorPosition test if within {@link $value}
*/
public function valid() {
return isset($this->iteratorKeys[$this->iteratorPosition]) && isset($this->value[$this->iteratorKeys[$this->iteratorPosition]]);
}
}
?>

View File

@@ -0,0 +1,742 @@
<?php
/**
* Data-Types for CFPropertyList as defined by Apple.
* {@link http://developer.apple.com/documentation/Darwin/Reference/ManPages/man5/plist.5.html Property Lists}
* @author Rodney Rehm <rodney.rehm@medialize.de>
* @author Christian Kruse <cjk@wwwtech.de>
* @package plist
* @subpackage plist.types
* @version $Id$
*/
/**
* Base-Class of all CFTypes used by CFPropertyList
* @author Rodney Rehm <rodney.rehm@medialize.de>
* @author Christian Kruse <cjk@wwwtech.de>
* @package plist
* @subpackage plist.types
* @version $Id$
* @example example-create-01.php Using the CFPropertyList API
* @example example-create-02.php Using CFPropertyList::guess()
* @example example-create-03.php Using CFPropertyList::guess() with {@link CFDate} and {@link CFData}
*/
abstract class CFType {
/**
* CFType nodes
* @var array
*/
protected $value = null;
/**
* Create new CFType.
* @param mixed $value Value of CFType
*/
public function __construct($value=null) {
$this->setValue($value);
}
/************************************************************************************************
* M A G I C P R O P E R T I E S
************************************************************************************************/
/**
* Get the CFType's value
* @return mixed CFType's value
*/
public function getValue() {
return $this->value;
}
/**
* Set the CFType's value
* @return void
*/
public function setValue($value) {
$this->value = $value;
}
/************************************************************************************************
* S E R I A L I Z I N G
************************************************************************************************/
/**
* Get XML-Node.
* @param DOMDocument $doc DOMDocument to create DOMNode in
* @param string $nodeName Name of element to create
* @return DOMNode Node created based on CType
* @uses $value as nodeValue
*/
public function toXML(DOMDocument $doc, $nodeName) {
$text = $doc->createTextNode($this->value);
$node = $doc->createElement($nodeName);
$node->appendChild($text);
return $node;
}
/**
* convert value to binary representation
* @param CFBinaryPropertyList The binary property list object
* @return The offset in the object table
*/
public abstract function toBinary(CFBinaryPropertyList &$bplist);
/**
* Get CFType's value.
* @return mixed primitive value
* @uses $value for retrieving primitive of CFType
*/
public function toArray() {
return $this->getValue();
}
}
/**
* String Type of CFPropertyList
* @author Rodney Rehm <rodney.rehm@medialize.de>
* @author Christian Kruse <cjk@wwwtech.de>
* @package plist
* @subpackage plist.types
*/
class CFString extends CFType {
/**
* Get XML-Node.
* @param DOMDocument $doc DOMDocument to create DOMNode in
* @param string $nodeName For compatibility reasons; just ignore it
* @return DOMNode &lt;string&gt;-Element
*/
public function toXML(DOMDocument $doc,$nodeName="") {
return parent::toXML($doc, 'string');
}
/**
* convert value to binary representation
* @param CFBinaryPropertyList The binary property list object
* @return The offset in the object table
*/
public function toBinary(CFBinaryPropertyList &$bplist) {
return $bplist->stringToBinary($this->value);
}
}
/**
* Number Type of CFPropertyList
* @author Rodney Rehm <rodney.rehm@medialize.de>
* @author Christian Kruse <cjk@wwwtech.de>
* @package plist
* @subpackage plist.types
*/
class CFNumber extends CFType {
/**
* Get XML-Node.
* Returns &lt;real&gt; if $value is a float, &lt;integer&gt; if $value is an integer.
* @param DOMDocument $doc DOMDocument to create DOMNode in
* @param string $nodeName For compatibility reasons; just ignore it
* @return DOMNode &lt;real&gt; or &lt;integer&gt;-Element
*/
public function toXML(DOMDocument $doc,$nodeName="") {
$ret = 'real';
if(intval($this->value) == $this->value && !is_float($this->value) && strpos($this->value,'.') === false) {
$this->value = intval($this->value);
$ret = 'integer';
}
return parent::toXML($doc, $ret);
}
/**
* convert value to binary representation
* @param CFBinaryPropertyList The binary property list object
* @return The offset in the object table
*/
public function toBinary(CFBinaryPropertyList &$bplist) {
return $bplist->numToBinary($this->value);
}
}
/**
* Date Type of CFPropertyList
* Note: CFDate uses Unix timestamp (epoch) to store dates internally
* @author Rodney Rehm <rodney.rehm@medialize.de>
* @author Christian Kruse <cjk@wwwtech.de>
* @package plist
* @subpackage plist.types
*/
class CFDate extends CFType {
const TIMESTAMP_APPLE = 0;
const TIMESTAMP_UNIX = 1;
const DATE_DIFF_APPLE_UNIX = 978307200;
/**
* Create new Date CFType.
* @param integer $value timestamp to set
* @param integer $format format the timestamp is specified in, use {@link TIMESTAMP_APPLE} or {@link TIMESTAMP_UNIX}, defaults to {@link TIMESTAMP_APPLE}
* @uses setValue() to convert the timestamp
*/
function __construct($value,$format=CFDate::TIMESTAMP_UNIX) {
$this->setValue($value,$format);
}
/**
* Set the Date CFType's value.
* @param integer $value timestamp to set
* @param integer $format format the timestamp is specified in, use {@link TIMESTAMP_APPLE} or {@link TIMESTAMP_UNIX}, defaults to {@link TIMESTAMP_UNIX}
* @return void
* @uses TIMESTAMP_APPLE to determine timestamp type
* @uses TIMESTAMP_UNIX to determine timestamp type
* @uses DATE_DIFF_APPLE_UNIX to convert Apple-timestamp to Unix-timestamp
*/
function setValue($value,$format=CFDate::TIMESTAMP_UNIX) {
if($format == CFDate::TIMESTAMP_UNIX) $this->value = $value;
else $this->value = $value + CFDate::DATE_DIFF_APPLE_UNIX;
}
/**
* Get the Date CFType's value.
* @param integer $format format the timestamp is specified in, use {@link TIMESTAMP_APPLE} or {@link TIMESTAMP_UNIX}, defaults to {@link TIMESTAMP_UNIX}
* @return integer Unix timestamp
* @uses TIMESTAMP_APPLE to determine timestamp type
* @uses TIMESTAMP_UNIX to determine timestamp type
* @uses DATE_DIFF_APPLE_UNIX to convert Unix-timestamp to Apple-timestamp
*/
function getValue($format=CFDate::TIMESTAMP_UNIX) {
if($format == CFDate::TIMESTAMP_UNIX) return $this->value;
else return $this->value - CFDate::DATE_DIFF_APPLE_UNIX;
}
/**
* Get XML-Node.
* @param DOMDocument $doc DOMDocument to create DOMNode in
* @param string $nodeName For compatibility reasons; just ignore it
* @return DOMNode &lt;date&gt;-Element
*/
public function toXML(DOMDocument $doc,$nodeName="") {
$text = $doc->createTextNode(gmdate("Y-m-d\TH:i:s\Z",$this->getValue()));
$node = $doc->createElement("date");
$node->appendChild($text);
return $node;
}
/**
* convert value to binary representation
* @param CFBinaryPropertyList The binary property list object
* @return The offset in the object table
*/
public function toBinary(CFBinaryPropertyList &$bplist) {
return $bplist->dateToBinary($this->value);
}
/**
* Create a UNIX timestamp from a PList date string
* @param string $val The date string (e.g. "2009-05-13T20:23:43Z")
* @return integer The UNIX timestamp
* @throws PListException when encountering an unknown date string format
*/
public static function dateValue($val) {
//2009-05-13T20:23:43Z
if(!preg_match('/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})Z/',$val,$matches)) throw new PListException("Unknown date format: $val");
return gmmktime($matches[4],$matches[5],$matches[6],$matches[2],$matches[3],$matches[1]);
}
}
/**
* Boolean Type of CFPropertyList
* @author Rodney Rehm <rodney.rehm@medialize.de>
* @author Christian Kruse <cjk@wwwtech.de>
* @package plist
* @subpackage plist.types
*/
class CFBoolean extends CFType {
/**
* Get XML-Node.
* Returns &lt;true&gt; if $value is a true, &lt;false&gt; if $value is false.
* @param DOMDocument $doc DOMDocument to create DOMNode in
* @param string $nodeName For compatibility reasons; just ignore it
* @return DOMNode &lt;true&gt; or &lt;false&gt;-Element
*/
public function toXML(DOMDocument $doc,$nodeName="") {
return $doc->createElement($this->value ? 'true' : 'false');
}
/**
* convert value to binary representation
* @param CFBinaryPropertyList The binary property list object
* @return The offset in the object table
*/
public function toBinary(CFBinaryPropertyList &$bplist) {
return $bplist->boolToBinary($this->value);
}
}
/**
* Data Type of CFPropertyList
* Note: Binary data is base64-encoded.
* @author Rodney Rehm <rodney.rehm@medialize.de>
* @author Christian Kruse <cjk@wwwtech.de>
* @package plist
* @subpackage plist.types
*/
class CFData extends CFType {
/**
* Create new Data CFType
* @param string $value data to be contained by new object
* @param boolean $already_coded if true $value will not be base64-encoded, defaults to false
*/
public function __construct($value=null,$already_coded=false) {
if($already_coded) $this->value = $value;
else $this->setValue($value);
}
/**
* Set the CFType's value and base64-encode it.
* <b>Note:</b> looks like base64_encode has troubles with UTF-8 encoded strings
* @return void
*/
public function setValue($value) {
//if(function_exists('mb_check_encoding') && mb_check_encoding($value, 'UTF-8')) $value = utf8_decode($value);
$this->value = base64_encode($value);
}
/**
* Get base64 encoded data
* @return string The base64 encoded data value
*/
public function getCodedValue() {
return $this->value;
}
/**
* Get the base64-decoded CFType's value.
* @return mixed CFType's value
*/
public function getValue() {
return base64_decode($this->value);
}
/**
* Get XML-Node.
* @param DOMDocument $doc DOMDocument to create DOMNode in
* @param string $nodeName For compatibility reasons; just ignore it
* @return DOMNode &lt;data&gt;-Element
*/
public function toXML(DOMDocument $doc,$nodeName="") {
return parent::toXML($doc, 'data');
}
/**
* convert value to binary representation
* @param CFBinaryPropertyList The binary property list object
* @return The offset in the object table
*/
public function toBinary(CFBinaryPropertyList &$bplist) {
return $bplist->dataToBinary($this->getValue());
}
}
/**
* Array Type of CFPropertyList
* @author Rodney Rehm <rodney.rehm@medialize.de>
* @author Christian Kruse <cjk@wwwtech.de>
* @package plist
* @subpackage plist.types
*/
class CFArray extends CFType implements Iterator, ArrayAccess {
/**
* Position of iterator {@link http://php.net/manual/en/class.iterator.php}
* @var integer
*/
protected $iteratorPosition = 0;
/**
* Create new CFType.
* @param array $value Value of CFType
*/
public function __construct($value=array()) {
$this->value = $value;
}
/**
* Set the CFType's value
* <b>Note:</b> this dummy does nothing
* @return void
*/
public function setValue($value) {
}
/**
* Add CFType to collection.
* @param CFType $value CFType to add to collection, defaults to null which results in an empty {@link CFString}
* @return void
* @uses $value for adding $value
*/
public function add(CFType $value=null) {
// anything but CFType is null, null is an empty string - sad but true
if( !$value )
$value = new CFString();
$this->value[] = $value;
}
/**
* Get CFType from collection.
* @param integer $key Key of CFType to retrieve from collection
* @return CFType CFType found at $key, null else
* @uses $value for retrieving CFType of $key
*/
public function get($key) {
if(isset($this->value[$key])) return $this->value[$key];
return null;
}
/**
* Remove CFType from collection.
* @param integer $key Key of CFType to removes from collection
* @return CFType removed CFType, null else
* @uses $value for removing CFType of $key
*/
public function del($key) {
if(isset($this->value[$key])) unset($this->value[$key]);
}
/************************************************************************************************
* S E R I A L I Z I N G
************************************************************************************************/
/**
* Get XML-Node.
* @param DOMDocument $doc DOMDocument to create DOMNode in
* @param string $nodeName For compatibility reasons; just ignore it
* @return DOMNode &lt;array&gt;-Element
*/
public function toXML(DOMDocument $doc,$nodeName="") {
$node = $doc->createElement('array');
foreach($this->value as $value) $node->appendChild($value->toXML($doc));
return $node;
}
/**
* convert value to binary representation
* @param CFBinaryPropertyList The binary property list object
* @return The offset in the object table
*/
public function toBinary(CFBinaryPropertyList &$bplist) {
return $bplist->arrayToBinary($this);
}
/**
* Get CFType's value.
* @return array primitive value
* @uses $value for retrieving primitive of CFType
*/
public function toArray() {
$a = array();
foreach($this->value as $value) $a[] = $value->toArray();
return $a;
}
/************************************************************************************************
* I T E R A T O R I N T E R F A C E
************************************************************************************************/
/**
* Rewind {@link $iteratorPosition} to first position (being 0)
* @link http://php.net/manual/en/iterator.rewind.php
* @return void
* @uses $iteratorPosition set to 0
*/
public function rewind() {
$this->iteratorPosition = 0;
}
/**
* Get Iterator's current {@link CFType} identified by {@link $iteratorPosition}
* @link http://php.net/manual/en/iterator.current.php
* @return CFType current Item
* @uses $iteratorPosition identify current key
*/
public function current() {
return $this->value[$this->iteratorPosition];
}
/**
* Get Iterator's current key identified by {@link $iteratorPosition}
* @link http://php.net/manual/en/iterator.key.php
* @return string key of the current Item
* @uses $iteratorPosition identify current key
*/
public function key() {
return $this->iteratorPosition;
}
/**
* Increment {@link $iteratorPosition} to address next {@see CFType}
* @link http://php.net/manual/en/iterator.next.php
* @return void
* @uses $iteratorPosition increment by 1
*/
public function next() {
$this->iteratorPosition++;
}
/**
* Test if {@link $iteratorPosition} addresses a valid element of {@link $value}
* @link http://php.net/manual/en/iterator.valid.php
* @return boolean true if current position is valid, false else
* @uses $iteratorPosition test if within {@link $iteratorKeys}
* @uses $iteratorPosition test if within {@link $value}
*/
public function valid() {
return isset($this->value[$this->iteratorPosition]);
}
/************************************************************************************************
* ArrayAccess I N T E R F A C E
************************************************************************************************/
/**
* Determine if the array's key exists
* @param string $key the key to check
* @return bool true if the offset exists, false if not
* @link http://php.net/manual/en/arrayaccess.offsetexists.php
* @uses $value to check if $key exists
* @author Sean Coates <sean@php.net>
*/
public function offsetExists($key) {
return isset($this->value[$key]);
}
/**
* Fetch a specific key from the CFArray
* @param string $key the key to check
* @return mixed the value associated with the key; null if the key is not found
* @link http://php.net/manual/en/arrayaccess.offsetget.php
* @uses get() to get the key's value
* @author Sean Coates <sean@php.net>
*/
public function offsetGet($key) {
return $this->get($key);
}
/**
* Set a value in the array
* @param string $key the key to set
* @param string $value the value to set
* @return void
* @link http://php.net/manual/en/arrayaccess.offsetset.php
* @uses setValue() to set the key's new value
* @author Sean Coates <sean@php.net>
*/
public function offsetSet($key, $value) {
return $this->setValue($value);
}
/**
* Unsets a value in the array
* <b>Note:</b> this dummy does nothing
* @param string $key the key to set
* @return void
* @link http://php.net/manual/en/arrayaccess.offsetunset.php
* @author Sean Coates <sean@php.net>
*/
public function offsetUnset($key) {
}
}
/**
* Array Type of CFPropertyList
* @author Rodney Rehm <rodney.rehm@medialize.de>
* @author Christian Kruse <cjk@wwwtech.de>
* @package plist
* @subpackage plist.types
*/
class CFDictionary extends CFType implements Iterator {
/**
* Position of iterator {@link http://php.net/manual/en/class.iterator.php}
* @var integer
*/
protected $iteratorPosition = 0;
/**
* List of Keys for numerical iterator access {@link http://php.net/manual/en/class.iterator.php}
* @var array
*/
protected $iteratorKeys = null;
/**
* Create new CFType.
* @param array $value Value of CFType
*/
public function __construct($value=array()) {
$this->value = $value;
}
/**
* Set the CFType's value
* <b>Note:</b> this dummy does nothing
* @return void
*/
public function setValue($value) {
}
/**
* Add CFType to collection.
* @param string $key Key to add to collection
* @param CFType $value CFType to add to collection, defaults to null which results in an empty {@link CFString}
* @return void
* @uses $value for adding $key $value pair
*/
public function add($key, CFType $value=null) {
// anything but CFType is null, null is an empty string - sad but true
if( !$value )
$value = new CFString();
$this->value[$key] = $value;
}
/**
* Get CFType from collection.
* @param string $key Key of CFType to retrieve from collection
* @return CFType CFType found at $key, null else
* @uses $value for retrieving CFType of $key
*/
public function get($key) {
if(isset($this->value[$key])) return $this->value[$key];
return null;
}
/**
* Generic getter (magic)
* @param integer $key Key of CFType to retrieve from collection
* @return CFType CFType found at $key, null else
* @link http://php.net/oop5.overloading
* @uses get() to retrieve the key's value
* @author Sean Coates <sean@php.net>
*/
public function __get($key) {
return $this->get($key);
}
/**
* Remove CFType from collection.
* @param string $key Key of CFType to removes from collection
* @return CFType removed CFType, null else
* @uses $value for removing CFType of $key
*/
public function del($key) {
if(isset($this->value[$key])) unset($this->value[$key]);
}
/************************************************************************************************
* S E R I A L I Z I N G
************************************************************************************************/
/**
* Get XML-Node.
* @param DOMDocument $doc DOMDocument to create DOMNode in
* @param string $nodeName For compatibility reasons; just ignore it
* @return DOMNode &lt;dict&gt;-Element
*/
public function toXML(DOMDocument $doc,$nodeName="") {
$node = $doc->createElement('dict');
foreach($this->value as $key => $value) {
$node->appendChild($doc->createElement('key', $key));
$node->appendChild($value->toXML($doc));
}
return $node;
}
/**
* convert value to binary representation
* @param CFBinaryPropertyList The binary property list object
* @return The offset in the object table
*/
public function toBinary(CFBinaryPropertyList &$bplist) {
return $bplist->dictToBinary($this);
}
/**
* Get CFType's value.
* @return array primitive value
* @uses $value for retrieving primitive of CFType
*/
public function toArray() {
$a = array();
foreach($this->value as $key => $value) $a[$key] = $value->toArray();
return $a;
}
/************************************************************************************************
* I T E R A T O R I N T E R F A C E
************************************************************************************************/
/**
* Rewind {@link $iteratorPosition} to first position (being 0)
* @link http://php.net/manual/en/iterator.rewind.php
* @return void
* @uses $iteratorPosition set to 0
* @uses $iteratorKeys store keys of {@link $value}
*/
public function rewind() {
$this->iteratorPosition = 0;
$this->iteratorKeys = array_keys($this->value);
}
/**
* Get Iterator's current {@link CFType} identified by {@link $iteratorPosition}
* @link http://php.net/manual/en/iterator.current.php
* @return CFType current Item
* @uses $iteratorPosition identify current key
* @uses $iteratorKeys identify current value
*/
public function current() {
return $this->value[$this->iteratorKeys[$this->iteratorPosition]];
}
/**
* Get Iterator's current key identified by {@link $iteratorPosition}
* @link http://php.net/manual/en/iterator.key.php
* @return string key of the current Item
* @uses $iteratorPosition identify current key
* @uses $iteratorKeys identify current value
*/
public function key() {
return $this->iteratorKeys[$this->iteratorPosition];
}
/**
* Increment {@link $iteratorPosition} to address next {@see CFType}
* @link http://php.net/manual/en/iterator.next.php
* @return void
* @uses $iteratorPosition increment by 1
*/
public function next() {
$this->iteratorPosition++;
}
/**
* Test if {@link $iteratorPosition} addresses a valid element of {@link $value}
* @link http://php.net/manual/en/iterator.valid.php
* @return boolean true if current position is valid, false else
* @uses $iteratorPosition test if within {@link $iteratorKeys}
* @uses $iteratorPosition test if within {@link $value}
*/
public function valid() {
return isset($this->iteratorKeys[$this->iteratorPosition]) && isset($this->value[$this->iteratorKeys[$this->iteratorPosition]]);
}
}
?>

View File

@@ -0,0 +1,167 @@
<?php
/**
* CFTypeDetector
* Interface for converting native PHP data structures to CFPropertyList objects.
* @author Rodney Rehm <rodney.rehm@medialize.de>
* @author Christian Kruse <cjk@wwwtech.de>
* @package plist
* @subpackage plist.types
* @example example-create-02.php Using {@link CFTypeDetector}
* @example example-create-03.php Using {@link CFTypeDetector} with {@link CFDate} and {@link CFData}
* @example example-create-04.php Using and extended {@link CFTypeDetector}
*/
class CFTypeDetector {
/**
* flag stating if all arrays should automatically be converted to {@link CFDictionary}
* @var boolean
*/
protected $autoDictionary = false;
/**
* flag stating if exceptions should be suppressed or thrown
* @var boolean
*/
protected $suppressExceptions = false;
/**
* name of a method that will be used for array to object conversations
* @var boolean
*/
protected $objectToArrayMethod = false;
/**
* Create new CFTypeDetector
* @param boolean $autoDicitionary if set to true all arrays will be converted to {@link CFDictionary}
* @param boolean $suppressExceptions if set to true toCFType() will not throw any exceptions
* @param boolean $objectToArrayMethod if non-null, this method will be called on objects (if possible) to convert the object to an array
*/
public function __construct($autoDicitionary=false,$suppressExceptions=false,$objectToArrayMethod=null) {
$this->autoDicitionary = $autoDicitionary;
$this->suppressExceptions = $suppressExceptions;
$this->objectToArrayMethod = $objectToArrayMethod;
}
/**
* Determine if an array is associative or numerical.
* Numerical Arrays have incrementing index-numbers that don't contain gaps.
* @param array $value Array to check indexes of
* @return boolean true if array is associative, false if array has numeric indexes
*/
protected function isAssociativeArray($value) {
$numericKeys = true;
$previousKey = null;
foreach($value as $key => $v) {
if(!is_numeric($key) || ($previousKey !== null && $previousKey != $key-1)) {
$numericKeys = false;
break;
}
$previousKey = $key;
}
return !$numericKeys;
}
/**
* Get the default value
* @return CFType the default value to return if no suitable type could be determined
*/
protected function defaultValue() {
return new CFString();
}
/**
* Create CFType-structure by guessing the data-types.
* {@link CFArray}, {@link CFDictionary}, {@link CFBoolean}, {@link CFNumber} and {@link CFString} can be created, {@link CFDate} and {@link CFData} cannot.
* <br /><b>Note:</b>Distinguishing between {@link CFArray} and {@link CFDictionary} is done by examining the keys.
* Keys must be strictly incrementing integers to evaluate to a {@link CFArray}.
* Since PHP does not offer a function to test for associative arrays,
* this test causes the input array to be walked twice and thus work rather slow on large collections.
* If you work with large arrays and can live with all arrays evaluating to {@link CFDictionary},
* feel free to set the appropriate flag.
* <br /><b>Note:</b> If $value is an instance of CFType it is simply returned.
* <br /><b>Note:</b> If $value is neither a CFType, array, numeric, boolean nor string, it is omitted.
* @param mixed $value Value to convert to CFType
* @param boolean $autoDictionary if true {@link CFArray}-detection is bypassed and arrays will be returned as {@link CFDictionary}.
* @return CFType CFType based on guessed type
* @uses isAssociativeArray() to check if an array only has numeric indexes
*/
public function toCFType($value) {
switch(true) {
case $value instanceof CFType:
return $value;
break;
case is_object($value):
// DateTime should be CFDate
if(class_exists( 'DateTime' ) && $value instanceof DateTime){
return new CFDate($value->getTimestamp());
}
// convert possible objects to arrays, arrays will be arrays
if($this->objectToArrayMethod && is_callable(array($value, $this->objectToArrayMethod))){
$value = call_user_func( array( $value, $this->objectToArrayMethod ) );
}
if(!is_array($value)){
if($this->suppressExceptions)
return $this->defaultValue();
throw new PListException('Could not determine CFType for object of type '. get_class($value));
}
/* break; omitted */
case $value instanceof Iterator:
case is_array($value):
// test if $value is simple or associative array
if(!$this->autoDictionary) {
if(!$this->isAssociativeArray($value)) {
$t = new CFArray();
foreach($value as $v) $t->add($this->toCFType($v));
return $t;
}
}
$t = new CFDictionary();
foreach($value as $k => $v) $t->add($k, $this->toCFType($v));
return $t;
break;
case is_numeric($value):
return new CFNumber($value);
break;
case is_bool($value):
return new CFBoolean($value);
break;
case is_string($value):
return new CFString($value);
break;
case is_null($value):
return new CFString();
break;
case is_resource($value):
if( $this->suppressExceptions )
return $this->defaultValue();
throw new PListException('Could not determine CFType for resource of type '. get_resource_type($value));
break;
default:
if( $this->suppressExceptions )
return $this->defaultValue();
throw new PListException('Could not determine CFType for '. gettype($value));
break;
}
}
}
?>

View File

@@ -0,0 +1,99 @@
<?php
/**
* CFPropertyList
* {@link http://developer.apple.com/documentation/Darwin/Reference/ManPages/man5/plist.5.html Property Lists}
* @author Rodney Rehm <rodney.rehm@medialize.de>
* @author Christian Kruse <cjk@wwwtech.de>
* @package plist
* @version $Id$
*/
/**
* Basic Input / Output Exception
* @author Rodney Rehm <rodney.rehm@medialize.de>
* @author Christian Kruse <cjk@wwwtech.de>
* @package plist
*/
class IOException extends Exception {
/**
* Flag telling the File could not be found
*/
const NOT_FOUND = 1;
/**
* Flag telling the File is not readable
*/
const NOT_READABLE = 2;
/**
* Flag telling the File is not writable
*/
const NOT_WRITABLE = 3;
/**
* Flag telling there was a read error
*/
const READ_ERROR = 4;
/**
* Flag telling there was a read error
*/
const WRITE_ERROR = 5;
/**
* Create new IOException
* @param string $path Source of the problem
* @param integer $type Type of the problem
*/
public function __construct($path, $type=null) {
parent::__construct( $path, $type );
}
/**
* Create new FileNotFound-Exception
* @param string $path Source of the problem
* @return IOException new FileNotFound-Exception
*/
public static function notFound($path) {
return new IOException( $path, self::NOT_FOUND );
}
/**
* Create new FileNotReadable-Exception
* @param string $path Source of the problem
* @return IOException new FileNotReadable-Exception
*/
public static function notReadable($path) {
return new IOException( $path, self::NOT_READABLE );
}
/**
* Create new FileNotWritable-Exception
* @param string $path Source of the problem
* @return IOException new FileNotWritable-Exception
*/
public static function notWritable($path) {
return new IOException( $path, self::NOT_WRITABLE );
}
/**
* Create new ReadError-Exception
* @param string $path Source of the problem
* @return IOException new ReadError-Exception
*/
public static function readError($path) {
return new IOException( $path, self::READ_ERROR );
}
/**
* Create new WriteError-Exception
* @param string $path Source of the problem
* @return IOException new WriteError-Exception
*/
public static function writeError($path) {
return new IOException( $path, self::WRITE_ERROR );
}
}
?>

View File

@@ -0,0 +1,22 @@
<?php
/**
* CFPropertyList
* {@link http://developer.apple.com/documentation/Darwin/Reference/ManPages/man5/plist.5.html Property Lists}
* @author Rodney Rehm <rodney.rehm@medialize.de>
* @author Christian Kruse <cjk@wwwtech.de>
* @package plist
* @version $Id$
*/
/**
* Exception for errors with the PList format
* @author Rodney Rehm <rodney.rehm@medialize.de>
* @author Christian Kruse <cjk@wwwtech.de>
* @package plist
*/
class PListException extends Exception {
}
?>

View File

@@ -0,0 +1,86 @@
<?php
/**
* Plist Format for Restler Framework.
* Plist is the native data exchange format for Apple iOS and Mac platform.
* Use this format to talk to mac applications and iOS devices.
* This class is capable of serving both xml plist and binary plist.
* @category Framework
* @package restler
* @subpackage format
* @author R.Arul Kumaran <arul@luracast.com>
* @copyright 2010 Luracast
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link http://luracast.com/products/restler/
*/
class PlistFormat implements iFormat
{
public static $binary_mode = false;
const MIME_BINARY = 'application/x-plist';
const MIME_XML = 'application/xml';
const EXTENSION_BINARY = 'bplist';
const EXTENSION_XML = 'plist';
public function getMIMEMap(){
return array(
PlistFormat::EXTENSION_BINARY=>PlistFormat::MIME_BINARY,
PlistFormat::EXTENSION_XML=>PlistFormat::MIME_XML
);
}
public function getMIME(){
return PlistFormat::$binary_mode ? PlistFormat::MIME_BINARY : PlistFormat::MIME_XML;
}
public function getExtension(){
return PlistFormat::$binary_mode ? PlistFormat::EXTENSION_BINARY : PlistFormat::EXTENSION_XML;
}
public function setMIME($mime){
PlistFormat::$binary_mode = $mime==PlistFormat::MIME_BINARY;
}
public function setExtension($extension){
PlistFormat::$binary_mode = $extension==PlistFormat::EXTENSION_BINARY;
}
/**
* Encode the given data in plist format
* @param array $data resulting data that needs to
* be encoded in plist format
* @param boolean $human_readable set to true when restler
* is not running in production mode. Formatter has to
* make the encoded output more human readable
* @return string encoded string
*/
public function encode($data, $human_readable=false){
require_once'CFPropertyList.php';
if(!PlistFormat::$binary_mode) {
PlistFormat::$binary_mode = !$human_readable;
} else {
$human_readable=false;
}
/**
* @var CFPropertyList
*/
$plist = new CFPropertyList();
$td = new CFTypeDetector();
$guessedStructure = $td->toCFType(object_to_array($data));
$plist->add( $guessedStructure );
return $human_readable ? $plist->toXML(true) : $plist->toBinary();
}
/**
* Decode the given data from plist format
* @param string $data data sent from client to
* the api in the given format.
* @return array associative array of the parsed data
*/
public function decode($data){
require_once'CFPropertyList.php';
$plist = new CFPropertyList();
$plist->parse($data);
return $plist->toArray();
}
public function __toString(){
return $this->getExtension();
}
}

1454
gulliver/thirdparty/restler/restler.php vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,213 @@
<?php
/**
* XML Markup Format for Restler Framework
* @category Framework
* @package restler
* @subpackage format
* @author R.Arul Kumaran <arul@luracast.com>
* @copyright 2010 Luracast
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link http://luracast.com/products/restler/
*/
class XmlFormat implements iFormat
{
public static $parse_attributes=true;
public static $parse_namespaces=false;
public static $attribute_names=array('xmlns');
/**
* Default name for the root node.
* @var string $rootNodeName
*/
public static $root_name='response';
public static $default_tag_name='item';
public static $mime = 'application/xml';
const MIME = 'application/xml,text/xml';
const EXTENSION = 'xml';
public function getMIMEMap()
{
return array(self::EXTENSION=>self::MIME);
}
public function getMIME(){
return self::$mime;
}
public function getExtension(){
return self::EXTENSION;
}
public function setMIME($mime){
self::$mime = $mime;
}
public function setExtension($extension){
//do nothing
}
public function encode($data, $human_readable=false){
return $this->toXML( object_to_array($data, false),
self::$root_name, $human_readable);
}
public function decode($data){
try {
if($data=='')return array();
return $this->toArray($data);
} catch (Exception $e) {
throw new RestException(400, "Error decoding request. ".
$e->getMessage());
}
}
public function __toString(){
return $this->getExtension();
}
/**
* determine if a variable is an associative array
*/
public function isAssoc( $array ) {
return (is_array($array) && 0 !== count(array_diff_key($array,
array_keys(array_keys($array)))));
}
/**
* The main function for converting to an XML document.
* Pass in a multi dimensional array and this recrusively loops through
* and builds up an XML document.
* @param array $data
* @param string $rootNodeName - what you want the root node to be -
* defaults to data.
* @param SimpleXMLElement $xml - should only be used recursively
* @return string XML
* @link http://bit.ly/n85yLi
*/
public function toXML( $data, $root_node_name = 'result',
$human_readable=false, &$xml=null) {
// turn off compatibility mode as simple xml
//throws a wobbly if you don't.
if (ini_get('zend.ze1_compatibility_mode') == 1)
ini_set ('zend.ze1_compatibility_mode', 0);
if (is_null($xml))
$xml = @simplexml_load_string("<$root_node_name/>");
if(is_array($data)){
$numeric=0;
// loop through the data passed in.
foreach( $data as $key => $value ) {
// no numeric keys in our xml please!
if ( is_numeric( $key ) ) {
$numeric = 1;
$key = self::$root_name == $root_node_name ?
self::$default_tag_name : $root_node_name;
}
// delete any char not allowed in XML element names
$key = preg_replace('/[^a-z0-9\-\_\.\:]/i', '', $key);
// if there is another array found recrusively
//call this function
if ( is_array( $value ) ) {
$node = $this->isAssoc( $value ) || $numeric ?
$xml->addChild( $key ) : $xml;
// recrusive call.
if ( $numeric ) $key = 'anon';
$this->toXML($value, $key, $human_readable, $node);
} else {
// add single node or attribute
$value=htmlspecialchars($value);
in_array($key,self::$attribute_names) ?
$xml->addAttribute($key,$value) :
$xml->addChild( $key, $value);
}
}
}else{ //if given data is a string or number
//simply wrap it as text node to root
if(is_bool($data)) $data = $data ? 'true' : 'false';
$xml = @simplexml_load_string(
"<$root_node_name>".htmlspecialchars($data)."</$root_node_name>");
//$xml->{0} = $data;
}
if(!$human_readable){
return $xml->asXML();
}else{
$dom = dom_import_simplexml($xml)->ownerDocument;
$dom->formatOutput = true;
return $dom->saveXML();
}
}
/**
* Convert an XML document to a multi dimensional array
* Pass in an XML document (or SimpleXMLElement object) and this
* recrusively loops through and builds a representative array
*
* @param string $xml - XML document - can optionally be a
* SimpleXMLElement object
* @return array ARRAY
* @link http://bit.ly/n85yLi
*/
public function toArray( $xml, $firstCall=true) {
if ( is_string( $xml ) ) $xml = new SimpleXMLElement( $xml );
$children = $xml->children();
if ( !$children ) {
$r = (string) $xml;
if($r=='true' || $r=='false')$r=$r=='true';
return $r;
}
$arr = array();
if($firstCall){
//reset the attribute names list
self::$attribute_names=array();
self::$root_name = $xml->getName();
if (self::$parse_namespaces){
foreach($xml->getDocNamespaces(TRUE) as $namepace => $uri) {
$arr[$namepace=='' ? 'xmlns' :
'xmlns:'.$namepace] = (string)$uri;
}
}
}
if(self::$parse_attributes){
foreach($xml->attributes() as $attName => $attValue) {
$arr[$attName] = (string)$attValue;
//add to attribute list for round trip support
self::$attribute_names[]=$attName;
}
}
foreach ($children as $key => $node) {
$node = $this->toArray($node, false);
// support for 'anon' non-associative arrays
if ($key == 'anon') $key = count($arr);
// if the node is already set, put it into an array
if (isset($arr[$key])) {
if ( !is_array($arr[$key]) || @$arr[$key][0] == null )
$arr[$key] = array($arr[$key]);
$arr[$key][] = $node;
} else {
$arr[$key] = $node;
}
}
return $arr;
}
/**
* When you decode an XML its structure is copied to the static vars
* we can use this function to echo them out and then copy paste inside
* our service methods
* @return string PHP source code to reproduce the configuration
*/
public static function exportCurrentSettings() {
$s = 'self::$root_name = "'.
(self::$root_name)."\";\n";
$s .= 'self::$attribute_names = '.
(var_export(self::$attribute_names, true)).";\n";
$s .= 'self::$default_tag_name = "'.
self::$default_tag_name."\";\n";
$s .= 'self::$parse_attributes = '.
(self::$parse_attributes ? 'true' : 'false').";\n";
$s .= 'self::$parse_namespaces = '.
(self::$parse_namespaces ? 'true' : 'false').";\n\n\n";
return $s;
}
}

View File

@@ -0,0 +1,19 @@
Copyright (c) 2008-2009 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,15 @@
Symfony YAML: A PHP library that speaks YAML
============================================
Symfony YAML is a PHP library that parses YAML strings and converts them to
PHP arrays. It can also converts PHP arrays to YAML strings. Its official
website is at http://components.symfony-project.org/yaml/.
The documentation is to be found in the `doc/` directory.
Symfony YAML is licensed under the MIT license (see LICENSE file).
The Symfony YAML library is developed and maintained by the
[symfony](http://www.symfony-project.org/) project team. It has been extracted
from symfony to be used as a standalone library. Symfony YAML is part of the
[symfony components project](http://components.symfony-project.org/).

View File

@@ -0,0 +1,137 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
include_once 'sfyamlinline.php';
/**
* sfYaml offers convenience methods to load and dump YAML.
*
* @package symfony
* @subpackage yaml
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfYaml.class.php 8988 2008-05-15 20:24:26Z fabien $
*/
class sfYaml
{
static protected
$spec = '1.2';
/**
* Sets the YAML specification version to use.
*
* @param string $version The YAML specification version
*/
static public function setSpecVersion($version)
{
if (!in_array($version, array('1.1', '1.2')))
{
throw new InvalidArgumentException(sprintf('Version %s of the YAML specifications is not supported', $version));
}
self::$spec = $version;
}
/**
* Gets the YAML specification version to use.
*
* @return string The YAML specification version
*/
static public function getSpecVersion()
{
return self::$spec;
}
/**
* Loads YAML into a PHP array.
*
* The load method, when supplied with a YAML stream (string or file),
* will do its best to convert YAML in a file into a PHP array.
*
* Usage:
* <code>
* $array = sfYaml::load('config.yml');
* print_r($array);
* </code>
*
* @param string $input Path of YAML file or string containing YAML
*
* @return array The YAML converted to a PHP array
*
* @throws InvalidArgumentException If the YAML is not valid
*/
public static function load($input)
{
$file = '';
// if input is a file, process it
if (strpos($input, "\n") === false && is_file($input))
{
$file = $input;
ob_start();
$retval = include($input);
$content = ob_get_clean();
// if an array is returned by the config file assume it's in plain php form else in YAML
$input = is_array($retval) ? $retval : $content;
}
// if an array is returned by the config file assume it's in plain php form else in YAML
if (is_array($input))
{
return $input;
}
require_once dirname(__FILE__).'/sfYamlParser.php';
$yaml = new sfYamlParser();
try
{
$ret = $yaml->parse($input);
}
catch (Exception $e)
{
throw new InvalidArgumentException(sprintf('Unable to parse %s: %s', $file ? sprintf('file "%s"', $file) : 'string', $e->getMessage()));
}
return $ret;
}
/**
* Dumps a PHP array to a YAML string.
*
* The dump method, when supplied with an array, will do its best
* to convert the array into friendly YAML.
*
* @param array $array PHP array
* @param integer $inline The level where you switch to inline YAML
*
* @return string A YAML string representing the original PHP array
*/
public static function dump($array, $inline = 2)
{
require_once dirname(__FILE__).'/sfyamldumper.php';
$yaml = new sfYamlDumper();
return $yaml->dump($array, $inline);
}
}
/**
* Wraps echo to automatically provide a newline.
*
* @param string $string The string to echo with new line
*/
function echoln($string)
{
echo $string."\n";
}

View File

@@ -0,0 +1,60 @@
<?php
/*
* This file is part of the symfony package.
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
//require_once(dirname(__FILE__).'/sfYamlInline.php');
/**
* sfYamlDumper dumps PHP variables to YAML strings.
*
* @package symfony
* @subpackage yaml
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfYamlDumper.class.php 10575 2008-08-01 13:08:42Z nicolas $
*/
class sfYamlDumper
{
/**
* Dumps a PHP value to YAML.
*
* @param mixed $input The PHP value
* @param integer $inline The level where you switch to inline YAML
* @param integer $indent The level o indentation indentation (used internally)
*
* @return string The YAML representation of the PHP value
*/
public function dump($input, $inline = 0, $indent = 0)
{
$output = '';
$prefix = $indent ? str_repeat(' ', $indent) : '';
if ($inline <= 0 || !is_array($input) || empty($input))
{
$output .= $prefix.sfYamlInline::dump($input);
}
else
{
$isAHash = array_keys($input) !== range(0, count($input) - 1);
foreach ($input as $key => $value)
{
$willBeInlined = $inline - 1 <= 0 || !is_array($value) || empty($value);
$output .= sprintf('%s%s%s%s',
$prefix,
$isAHash ? sfYamlInline::dump($key).':' : '-',
$willBeInlined ? ' ' : "\n",
$this->dump($value, $inline - 1, $willBeInlined ? 0 : $indent + 2)
).($willBeInlined ? "\n" : '');
}
}
return $output;
}
}

View File

@@ -0,0 +1,442 @@
<?php
/*
* This file is part of the symfony package.
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
//require_once dirname(__FILE__).'/sfYaml.php';
/**
* sfYamlInline implements a YAML parser/dumper for the YAML inline syntax.
*
* @package symfony
* @subpackage yaml
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfYamlInline.class.php 16177 2009-03-11 08:32:48Z fabien $
*/
class sfYamlInline
{
const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\']*(?:\'\'[^\']*)*)\')';
/**
* Convert a YAML string to a PHP array.
*
* @param string $value A YAML string
*
* @return array A PHP array representing the YAML string
*/
static public function load($value)
{
$value = trim($value);
if (0 == strlen($value))
{
return '';
}
if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2)
{
$mbEncoding = mb_internal_encoding();
mb_internal_encoding('ASCII');
}
switch ($value[0])
{
case '[':
$result = self::parseSequence($value);
break;
case '{':
$result = self::parseMapping($value);
break;
default:
$result = self::parseScalar($value);
}
if (isset($mbEncoding))
{
mb_internal_encoding($mbEncoding);
}
return $result;
}
/**
* Dumps a given PHP variable to a YAML string.
*
* @param mixed $value The PHP variable to convert
*
* @return string The YAML string representing the PHP array
*/
static public function dump($value)
{
if ('1.1' === sfYaml::getSpecVersion())
{
$trueValues = array('true', 'on', '+', 'yes', 'y');
$falseValues = array('false', 'off', '-', 'no', 'n');
}
else
{
$trueValues = array('true');
$falseValues = array('false');
}
switch (true)
{
case is_resource($value):
throw new InvalidArgumentException('Unable to dump PHP resources in a YAML file.');
case is_object($value):
return '!!php/object:'.serialize($value);
case is_array($value):
return self::dumpArray($value);
case null === $value:
return 'null';
case true === $value:
return 'true';
case false === $value:
return 'false';
case ctype_digit($value):
return is_string($value) ? "'$value'" : (int) $value;
case is_numeric($value):
return is_infinite($value) ? str_ireplace('INF', '.Inf', strval($value)) : (is_string($value) ? "'$value'" : $value);
case false !== strpos($value, "\n") || false !== strpos($value, "\r"):
return sprintf('"%s"', str_replace(array('"', "\n", "\r"), array('\\"', '\n', '\r'), $value));
case preg_match('/[ \s \' " \: \{ \} \[ \] , & \* \# \?] | \A[ - ? | < > = ! % @ ` ]/x', $value):
return sprintf("'%s'", str_replace('\'', '\'\'', $value));
case '' == $value:
return "''";
case preg_match(self::getTimestampRegex(), $value):
return "'$value'";
case in_array(strtolower($value), $trueValues):
return "'$value'";
case in_array(strtolower($value), $falseValues):
return "'$value'";
case in_array(strtolower($value), array('null', '~')):
return "'$value'";
default:
return $value;
}
}
/**
* Dumps a PHP array to a YAML string.
*
* @param array $value The PHP array to dump
*
* @return string The YAML string representing the PHP array
*/
static protected function dumpArray($value)
{
// array
$keys = array_keys($value);
if (
(1 == count($keys) && '0' == $keys[0])
||
(count($keys) > 1 && array_reduce($keys, create_function('$v,$w', 'return (integer) $v + $w;'), 0) == count($keys) * (count($keys) - 1) / 2))
{
$output = array();
foreach ($value as $val)
{
$output[] = self::dump($val);
}
return sprintf('[%s]', implode(', ', $output));
}
// mapping
$output = array();
foreach ($value as $key => $val)
{
$output[] = sprintf('%s: %s', self::dump($key), self::dump($val));
}
return sprintf('{ %s }', implode(', ', $output));
}
/**
* Parses a scalar to a YAML string.
*
* @param scalar $scalar
* @param string $delimiters
* @param array $stringDelimiter
* @param integer $i
* @param boolean $evaluate
*
* @return string A YAML string
*/
static public function parseScalar($scalar, $delimiters = null, $stringDelimiters = array('"', "'"), &$i = 0, $evaluate = true)
{
if (in_array($scalar[$i], $stringDelimiters))
{
// quoted scalar
$output = self::parseQuotedScalar($scalar, $i);
}
else
{
// "normal" string
if (!$delimiters)
{
$output = substr($scalar, $i);
$i += strlen($output);
// remove comments
if (false !== $strpos = strpos($output, ' #'))
{
$output = rtrim(substr($output, 0, $strpos));
}
}
else if (preg_match('/^(.+?)('.implode('|', $delimiters).')/', substr($scalar, $i), $match))
{
$output = $match[1];
$i += strlen($output);
}
else
{
throw new InvalidArgumentException(sprintf('Malformed inline YAML string (%s).', $scalar));
}
$output = $evaluate ? self::evaluateScalar($output) : $output;
}
return $output;
}
/**
* Parses a quoted scalar to YAML.
*
* @param string $scalar
* @param integer $i
*
* @return string A YAML string
*/
static protected function parseQuotedScalar($scalar, &$i)
{
if (!preg_match('/'.self::REGEX_QUOTED_STRING.'/Au', substr($scalar, $i), $match))
{
throw new InvalidArgumentException(sprintf('Malformed inline YAML string (%s).', substr($scalar, $i)));
}
$output = substr($match[0], 1, strlen($match[0]) - 2);
if ('"' == $scalar[$i])
{
// evaluate the string
$output = str_replace(array('\\"', '\\n', '\\r'), array('"', "\n", "\r"), $output);
}
else
{
// unescape '
$output = str_replace('\'\'', '\'', $output);
}
$i += strlen($match[0]);
return $output;
}
/**
* Parses a sequence to a YAML string.
*
* @param string $sequence
* @param integer $i
*
* @return string A YAML string
*/
static protected function parseSequence($sequence, &$i = 0)
{
$output = array();
$len = strlen($sequence);
$i += 1;
// [foo, bar, ...]
while ($i < $len)
{
switch ($sequence[$i])
{
case '[':
// nested sequence
$output[] = self::parseSequence($sequence, $i);
break;
case '{':
// nested mapping
$output[] = self::parseMapping($sequence, $i);
break;
case ']':
return $output;
case ',':
case ' ':
break;
default:
$isQuoted = in_array($sequence[$i], array('"', "'"));
$value = self::parseScalar($sequence, array(',', ']'), array('"', "'"), $i);
if (!$isQuoted && false !== strpos($value, ': '))
{
// embedded mapping?
try
{
$value = self::parseMapping('{'.$value.'}');
}
catch (InvalidArgumentException $e)
{
// no, it's not
}
}
$output[] = $value;
--$i;
}
++$i;
}
throw new InvalidArgumentException(sprintf('Malformed inline YAML string %s', $sequence));
}
/**
* Parses a mapping to a YAML string.
*
* @param string $mapping
* @param integer $i
*
* @return string A YAML string
*/
static protected function parseMapping($mapping, &$i = 0)
{
$output = array();
$len = strlen($mapping);
$i += 1;
// {foo: bar, bar:foo, ...}
while ($i < $len)
{
switch ($mapping[$i])
{
case ' ':
case ',':
++$i;
continue 2;
case '}':
return $output;
}
// key
$key = self::parseScalar($mapping, array(':', ' '), array('"', "'"), $i, false);
// value
$done = false;
while ($i < $len)
{
switch ($mapping[$i])
{
case '[':
// nested sequence
$output[$key] = self::parseSequence($mapping, $i);
$done = true;
break;
case '{':
// nested mapping
$output[$key] = self::parseMapping($mapping, $i);
$done = true;
break;
case ':':
case ' ':
break;
default:
$output[$key] = self::parseScalar($mapping, array(',', '}'), array('"', "'"), $i);
$done = true;
--$i;
}
++$i;
if ($done)
{
continue 2;
}
}
}
throw new InvalidArgumentException(sprintf('Malformed inline YAML string %s', $mapping));
}
/**
* Evaluates scalars and replaces magic values.
*
* @param string $scalar
*
* @return string A YAML string
*/
static protected function evaluateScalar($scalar)
{
$scalar = trim($scalar);
if ('1.1' === sfYaml::getSpecVersion())
{
$trueValues = array('true', 'on', '+', 'yes', 'y');
$falseValues = array('false', 'off', '-', 'no', 'n');
}
else
{
$trueValues = array('true');
$falseValues = array('false');
}
switch (true)
{
case 'null' == strtolower($scalar):
case '' == $scalar:
case '~' == $scalar:
return null;
case 0 === strpos($scalar, '!str'):
return (string) substr($scalar, 5);
case 0 === strpos($scalar, '! '):
return intval(self::parseScalar(substr($scalar, 2)));
case 0 === strpos($scalar, '!!php/object:'):
return unserialize(substr($scalar, 13));
case ctype_digit($scalar):
$raw = $scalar;
$cast = intval($scalar);
return '0' == $scalar[0] ? octdec($scalar) : (((string) $raw == (string) $cast) ? $cast : $raw);
case in_array(strtolower($scalar), $trueValues):
return true;
case in_array(strtolower($scalar), $falseValues):
return false;
case is_numeric($scalar):
return '0x' == $scalar[0].$scalar[1] ? hexdec($scalar) : floatval($scalar);
case 0 == strcasecmp($scalar, '.inf'):
case 0 == strcasecmp($scalar, '.NaN'):
return -log(0);
case 0 == strcasecmp($scalar, '-.inf'):
return log(0);
case preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $scalar):
return floatval(str_replace(',', '', $scalar));
case preg_match(self::getTimestampRegex(), $scalar):
return strtotime($scalar);
default:
return (string) $scalar;
}
}
static protected function getTimestampRegex()
{
return <<<EOF
~^
(?P<year>[0-9][0-9][0-9][0-9])
-(?P<month>[0-9][0-9]?)
-(?P<day>[0-9][0-9]?)
(?:(?:[Tt]|[ \t]+)
(?P<hour>[0-9][0-9]?)
:(?P<minute>[0-9][0-9])
:(?P<second>[0-9][0-9])
(?:\.(?P<fraction>[0-9]*))?
(?:[ \t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?)
(?::(?P<tz_minute>[0-9][0-9]))?))?)?
$~x
EOF;
}
}

View File

@@ -0,0 +1,622 @@
<?php
/*
* This file is part of the symfony package.
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
//require_once(dirname(__FILE__).'/sfYamlInline.php');
if (!defined('PREG_BAD_UTF8_OFFSET_ERROR'))
{
define('PREG_BAD_UTF8_OFFSET_ERROR', 5);
}
/**
* sfYamlParser parses YAML strings to convert them to PHP arrays.
*
* @package symfony
* @subpackage yaml
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfYamlParser.class.php 10832 2008-08-13 07:46:08Z fabien $
*/
class sfYamlParser
{
protected
$offset = 0,
$lines = array(),
$currentLineNb = -1,
$currentLine = '',
$refs = array();
/**
* Constructor
*
* @param integer $offset The offset of YAML document (used for line numbers in error messages)
*/
public function __construct($offset = 0)
{
$this->offset = $offset;
}
/**
* Parses a YAML string to a PHP value.
*
* @param string $value A YAML string
*
* @return mixed A PHP value
*
* @throws InvalidArgumentException If the YAML is not valid
*/
public function parse($value)
{
$this->currentLineNb = -1;
$this->currentLine = '';
$this->lines = explode("\n", $this->cleanup($value));
if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2)
{
$mbEncoding = mb_internal_encoding();
mb_internal_encoding('UTF-8');
}
$data = array();
while ($this->moveToNextLine())
{
if ($this->isCurrentLineEmpty())
{
continue;
}
// tab?
if (preg_match('#^\t+#', $this->currentLine))
{
throw new InvalidArgumentException(sprintf('A YAML file cannot contain tabs as indentation at line %d (%s).', $this->getRealCurrentLineNb() + 1, $this->currentLine));
}
$isRef = $isInPlace = $isProcessed = false;
if (preg_match('#^\-((?P<leadspaces>\s+)(?P<value>.+?))?\s*$#u', $this->currentLine, $values))
{
if (isset($values['value']) && preg_match('#^&(?P<ref>[^ ]+) *(?P<value>.*)#u', $values['value'], $matches))
{
$isRef = $matches['ref'];
$values['value'] = $matches['value'];
}
// array
if (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#'))
{
$c = $this->getRealCurrentLineNb() + 1;
$parser = new sfYamlParser($c);
$parser->refs =& $this->refs;
$data[] = $parser->parse($this->getNextEmbedBlock());
}
else
{
if (isset($values['leadspaces'])
&& ' ' == $values['leadspaces']
&& preg_match('#^(?P<key>'.sfYamlInline::REGEX_QUOTED_STRING.'|[^ \'"\{].*?) *\:(\s+(?P<value>.+?))?\s*$#u', $values['value'], $matches))
{
// this is a compact notation element, add to next block and parse
$c = $this->getRealCurrentLineNb();
$parser = new sfYamlParser($c);
$parser->refs =& $this->refs;
$block = $values['value'];
if (!$this->isNextLineIndented())
{
$block .= "\n".$this->getNextEmbedBlock($this->getCurrentLineIndentation() + 2);
}
$data[] = $parser->parse($block);
}
else
{
$data[] = $this->parseValue($values['value']);
}
}
}
else if (preg_match('#^(?P<key>'.sfYamlInline::REGEX_QUOTED_STRING.'|[^ \'"].*?) *\:(\s+(?P<value>.+?))?\s*$#u', $this->currentLine, $values))
{
$key = sfYamlInline::parseScalar($values['key']);
if ('<<' === $key)
{
if (isset($values['value']) && '*' === substr($values['value'], 0, 1))
{
$isInPlace = substr($values['value'], 1);
if (!array_key_exists($isInPlace, $this->refs))
{
throw new InvalidArgumentException(sprintf('Reference "%s" does not exist at line %s (%s).', $isInPlace, $this->getRealCurrentLineNb() + 1, $this->currentLine));
}
}
else
{
if (isset($values['value']) && $values['value'] !== '')
{
$value = $values['value'];
}
else
{
$value = $this->getNextEmbedBlock();
}
$c = $this->getRealCurrentLineNb() + 1;
$parser = new sfYamlParser($c);
$parser->refs =& $this->refs;
$parsed = $parser->parse($value);
$merged = array();
if (!is_array($parsed))
{
throw new InvalidArgumentException(sprintf("YAML merge keys used with a scalar value instead of an array at line %s (%s)", $this->getRealCurrentLineNb() + 1, $this->currentLine));
}
else if (isset($parsed[0]))
{
// Numeric array, merge individual elements
foreach (array_reverse($parsed) as $parsedItem)
{
if (!is_array($parsedItem))
{
throw new InvalidArgumentException(sprintf("Merge items must be arrays at line %s (%s).", $this->getRealCurrentLineNb() + 1, $parsedItem));
}
$merged = array_merge($parsedItem, $merged);
}
}
else
{
// Associative array, merge
$merged = array_merge($merged, $parsed);
}
$isProcessed = $merged;
}
}
else if (isset($values['value']) && preg_match('#^&(?P<ref>[^ ]+) *(?P<value>.*)#u', $values['value'], $matches))
{
$isRef = $matches['ref'];
$values['value'] = $matches['value'];
}
if ($isProcessed)
{
// Merge keys
$data = $isProcessed;
}
// hash
else if (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#'))
{
// if next line is less indented or equal, then it means that the current value is null
if ($this->isNextLineIndented())
{
$data[$key] = null;
}
else
{
$c = $this->getRealCurrentLineNb() + 1;
$parser = new sfYamlParser($c);
$parser->refs =& $this->refs;
$data[$key] = $parser->parse($this->getNextEmbedBlock());
}
}
else
{
if ($isInPlace)
{
$data = $this->refs[$isInPlace];
}
else
{
$data[$key] = $this->parseValue($values['value']);
}
}
}
else
{
// 1-liner followed by newline
if (2 == count($this->lines) && empty($this->lines[1]))
{
$value = sfYamlInline::load($this->lines[0]);
if (is_array($value))
{
$first = reset($value);
if ('*' === substr($first, 0, 1))
{
$data = array();
foreach ($value as $alias)
{
$data[] = $this->refs[substr($alias, 1)];
}
$value = $data;
}
}
if (isset($mbEncoding))
{
mb_internal_encoding($mbEncoding);
}
return $value;
}
switch (preg_last_error())
{
case PREG_INTERNAL_ERROR:
$error = 'Internal PCRE error on line';
break;
case PREG_BACKTRACK_LIMIT_ERROR:
$error = 'pcre.backtrack_limit reached on line';
break;
case PREG_RECURSION_LIMIT_ERROR:
$error = 'pcre.recursion_limit reached on line';
break;
case PREG_BAD_UTF8_ERROR:
$error = 'Malformed UTF-8 data on line';
break;
case PREG_BAD_UTF8_OFFSET_ERROR:
$error = 'Offset doesn\'t correspond to the begin of a valid UTF-8 code point on line';
break;
default:
$error = 'Unable to parse line';
}
throw new InvalidArgumentException(sprintf('%s %d (%s).', $error, $this->getRealCurrentLineNb() + 1, $this->currentLine));
}
if ($isRef)
{
$this->refs[$isRef] = end($data);
}
}
if (isset($mbEncoding))
{
mb_internal_encoding($mbEncoding);
}
return empty($data) ? null : $data;
}
/**
* Returns the current line number (takes the offset into account).
*
* @return integer The current line number
*/
protected function getRealCurrentLineNb()
{
return $this->currentLineNb + $this->offset;
}
/**
* Returns the current line indentation.
*
* @return integer The current line indentation
*/
protected function getCurrentLineIndentation()
{
return strlen($this->currentLine) - strlen(ltrim($this->currentLine, ' '));
}
/**
* Returns the next embed block of YAML.
*
* @param integer $indentation The indent level at which the block is to be read, or null for default
*
* @return string A YAML string
*/
protected function getNextEmbedBlock($indentation = null)
{
$this->moveToNextLine();
if (null === $indentation)
{
$newIndent = $this->getCurrentLineIndentation();
if (!$this->isCurrentLineEmpty() && 0 == $newIndent)
{
throw new InvalidArgumentException(sprintf('Indentation problem at line %d (%s)', $this->getRealCurrentLineNb() + 1, $this->currentLine));
}
}
else
{
$newIndent = $indentation;
}
$data = array(substr($this->currentLine, $newIndent));
while ($this->moveToNextLine())
{
if ($this->isCurrentLineEmpty())
{
if ($this->isCurrentLineBlank())
{
$data[] = substr($this->currentLine, $newIndent);
}
continue;
}
$indent = $this->getCurrentLineIndentation();
if (preg_match('#^(?P<text> *)$#', $this->currentLine, $match))
{
// empty line
$data[] = $match['text'];
}
else if ($indent >= $newIndent)
{
$data[] = substr($this->currentLine, $newIndent);
}
else if (0 == $indent)
{
$this->moveToPreviousLine();
break;
}
else
{
throw new InvalidArgumentException(sprintf('Indentation problem at line %d (%s)', $this->getRealCurrentLineNb() + 1, $this->currentLine));
}
}
return implode("\n", $data);
}
/**
* Moves the parser to the next line.
*/
protected function moveToNextLine()
{
if ($this->currentLineNb >= count($this->lines) - 1)
{
return false;
}
$this->currentLine = $this->lines[++$this->currentLineNb];
return true;
}
/**
* Moves the parser to the previous line.
*/
protected function moveToPreviousLine()
{
$this->currentLine = $this->lines[--$this->currentLineNb];
}
/**
* Parses a YAML value.
*
* @param string $value A YAML value
*
* @return mixed A PHP value
*/
protected function parseValue($value)
{
if ('*' === substr($value, 0, 1))
{
if (false !== $pos = strpos($value, '#'))
{
$value = substr($value, 1, $pos - 2);
}
else
{
$value = substr($value, 1);
}
if (!array_key_exists($value, $this->refs))
{
throw new InvalidArgumentException(sprintf('Reference "%s" does not exist (%s).', $value, $this->currentLine));
}
return $this->refs[$value];
}
if (preg_match('/^(?P<separator>\||>)(?P<modifiers>\+|\-|\d+|\+\d+|\-\d+|\d+\+|\d+\-)?(?P<comments> +#.*)?$/', $value, $matches))
{
$modifiers = isset($matches['modifiers']) ? $matches['modifiers'] : '';
return $this->parseFoldedScalar($matches['separator'], preg_replace('#\d+#', '', $modifiers), intval(abs($modifiers)));
}
else
{
return sfYamlInline::load($value);
}
}
/**
* Parses a folded scalar.
*
* @param string $separator The separator that was used to begin this folded scalar (| or >)
* @param string $indicator The indicator that was used to begin this folded scalar (+ or -)
* @param integer $indentation The indentation that was used to begin this folded scalar
*
* @return string The text value
*/
protected function parseFoldedScalar($separator, $indicator = '', $indentation = 0)
{
$separator = '|' == $separator ? "\n" : ' ';
$text = '';
$notEOF = $this->moveToNextLine();
while ($notEOF && $this->isCurrentLineBlank())
{
$text .= "\n";
$notEOF = $this->moveToNextLine();
}
if (!$notEOF)
{
return '';
}
if (!preg_match('#^(?P<indent>'.($indentation ? str_repeat(' ', $indentation) : ' +').')(?P<text>.*)$#u', $this->currentLine, $matches))
{
$this->moveToPreviousLine();
return '';
}
$textIndent = $matches['indent'];
$previousIndent = 0;
$text .= $matches['text'].$separator;
while ($this->currentLineNb + 1 < count($this->lines))
{
$this->moveToNextLine();
if (preg_match('#^(?P<indent> {'.strlen($textIndent).',})(?P<text>.+)$#u', $this->currentLine, $matches))
{
if (' ' == $separator && $previousIndent != $matches['indent'])
{
$text = substr($text, 0, -1)."\n";
}
$previousIndent = $matches['indent'];
$text .= str_repeat(' ', $diff = strlen($matches['indent']) - strlen($textIndent)).$matches['text'].($diff ? "\n" : $separator);
}
else if (preg_match('#^(?P<text> *)$#', $this->currentLine, $matches))
{
$text .= preg_replace('#^ {1,'.strlen($textIndent).'}#', '', $matches['text'])."\n";
}
else
{
$this->moveToPreviousLine();
break;
}
}
if (' ' == $separator)
{
// replace last separator by a newline
$text = preg_replace('/ (\n*)$/', "\n$1", $text);
}
switch ($indicator)
{
case '':
$text = preg_replace('#\n+$#s', "\n", $text);
break;
case '+':
break;
case '-':
$text = preg_replace('#\n+$#s', '', $text);
break;
}
return $text;
}
/**
* Returns true if the next line is indented.
*
* @return Boolean Returns true if the next line is indented, false otherwise
*/
protected function isNextLineIndented()
{
$currentIndentation = $this->getCurrentLineIndentation();
$notEOF = $this->moveToNextLine();
while ($notEOF && $this->isCurrentLineEmpty())
{
$notEOF = $this->moveToNextLine();
}
if (false === $notEOF)
{
return false;
}
$ret = false;
if ($this->getCurrentLineIndentation() <= $currentIndentation)
{
$ret = true;
}
$this->moveToPreviousLine();
return $ret;
}
/**
* Returns true if the current line is blank or if it is a comment line.
*
* @return Boolean Returns true if the current line is empty or if it is a comment line, false otherwise
*/
protected function isCurrentLineEmpty()
{
return $this->isCurrentLineBlank() || $this->isCurrentLineComment();
}
/**
* Returns true if the current line is blank.
*
* @return Boolean Returns true if the current line is blank, false otherwise
*/
protected function isCurrentLineBlank()
{
return '' == trim($this->currentLine, ' ');
}
/**
* Returns true if the current line is a comment line.
*
* @return Boolean Returns true if the current line is a comment line, false otherwise
*/
protected function isCurrentLineComment()
{
//checking explicitly the first char of the trim is faster than loops or strpos
$ltrimmedLine = ltrim($this->currentLine, ' ');
return $ltrimmedLine[0] === '#';
}
/**
* Cleanups a YAML string to be parsed.
*
* @param string $value The input YAML string
*
* @return string A cleaned up YAML string
*/
protected function cleanup($value)
{
$value = str_replace(array("\r\n", "\r"), "\n", $value);
if (!preg_match("#\n$#", $value))
{
$value .= "\n";
}
// strip YAML header
$count = 0;
$value = preg_replace('#^\%YAML[: ][\d\.]+.*\n#su', '', $value, -1, $count);
$this->offset += $count;
// remove leading comments
$trimmedValue = preg_replace('#^(\#.*?\n)+#s', '', $value, -1, $count);
if ($count == 1)
{
// items have been removed, update the offset
$this->offset += substr_count($value, "\n") - substr_count($trimmedValue, "\n");
$value = $trimmedValue;
}
// remove start of the document marker (---)
$trimmedValue = preg_replace('#^\-\-\-.*?\n#s', '', $value, -1, $count);
if ($count == 1)
{
// items have been removed, update the offset
$this->offset += substr_count($value, "\n") - substr_count($trimmedValue, "\n");
$value = $trimmedValue;
// remove end of the document marker (...)
$value = preg_replace('#\.\.\.\s*$#s', '', $value);
}
return $value;
}
}

View File

@@ -0,0 +1,47 @@
<?php
/**
* YAML Format for Restler Framework
* @category Framework
* @package restler
* @subpackage format
* @author R.Arul Kumaran <arul@luracast.com>
* @copyright 2010 Luracast
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link http://luracast.com/products/restler/
*/
class YamlFormat implements iFormat
{
const MIME ='text/plain';
const EXTENSION = 'yaml';
public function getMIMEMap()
{
return array(YamlFormat::EXTENSION=>YamlFormat::MIME);
}
public function getMIME(){
return YamlFormat::MIME;
}
public function getExtension(){
return YamlFormat::EXTENSION;
}
public function setMIME($mime){
//do nothing
}
public function setExtension($extension){
//do nothing
}
public function encode($data, $human_readable=false){
require_once 'sfyaml.php';
return sfYaml::dump(object_to_array($data));
}
public function decode($data){
require_once 'sfyaml.php';
return sfYaml::load($data);
}
public function __toString(){
return $this->getExtension();
}
}

View File

@@ -64,6 +64,7 @@
define( 'PATH_WORKFLOW_MSSQL_DATA', PATH_CORE . 'data' . PATH_SEP.'mssql'.PATH_SEP);
define( 'PATH_RBAC_MSSQL_DATA', PATH_RBAC_CORE . 'data' . PATH_SEP.'mssql'.PATH_SEP);
define( 'PATH_CONTROLLERS', PATH_CORE . 'controllers' . PATH_SEP );
define( 'PATH_SERVICES_REST', PATH_CORE . 'services' . PATH_SEP . 'rest' . PATH_SEP);
// include Gulliver Class
require_once( PATH_GULLIVER . PATH_SEP . 'class.g.php');

View File

@@ -0,0 +1,30 @@
<?php
class Author
{
public $dp;
static $FIELDS = array('name', 'email');
function __construct()
{
}
function get($id=NULL)
{
return is_null($id) ? 'GET: getting all records' : "Getting a record with id: $id";
}
function post($request_data=NULL)
{
return 'POST: posting 1';
}
function put($id=NULL, $request_data=NULL)
{
return 'PUT: update 1';
}
function delete($id=NULL) {
return 'DELETE: deleting '.$id;
}
}

View File

@@ -0,0 +1,37 @@
<?php
class BMI {
function index($height=162.6, $weight=84) {
$result = new stdClass();
# 1 pound = 0.45359237 kilograms
# 1 meter = 3.2808399 feet
# 1 meter = 39.3700787 inches
# 1 meter = 100 cms
#assume height is given in centimeters
$cm = $height;
#assume weight is given in kilograms
$kg = $weight;
$meter = $cm / 100;
$inches = $meter * 39.3700787;
$feet = round($inches/12);
$inches = $inches % 12;
$result->bmi = round($kg/($meter*$meter),2);
$lb = round($kg/0.45359237,2);
if($result->bmi<18.5){
$result->message = 'Underweight';
}elseif ($result->bmi<=24.9){
$result->message = 'Normal weight';
}elseif ($result->bmi<=29.9){
$result->message = 'Overweight';
}else{
$result->message = 'Obesity';
}
$result->metric = array('height'=>"$cm centimeter", 'weight'=>"$weight kilograms");
$result->imperial = array('height'=>"$feet feet $inches inches", 'weight'=>"$lb pounds");
return $result;
}
}

View File

@@ -0,0 +1,6 @@
<?php
class Say {
function hello($to='world') {
return "Hello $to!";
}
}

View File

@@ -0,0 +1,15 @@
<?php
class Simple {
function normal() {
return 'open for all';
}
protected function restricted() {
return 'protected method';
}
/**
* @protected
*/
function restricted2(){
return 'protected by comment';
}
}

View File

@@ -0,0 +1,16 @@
<?php
class SimpleAuth implements iAuthenticate
{
const KEY = 'sample';
function __isAuthenticated()
{
print_r($_SERVER);
return isset($_GET['key']) && $_GET['key']==SimpleAuth::KEY ? TRUE : FALSE;
}
function key()
{
return SimpleAuth::KEY;
}
}

View File

@@ -173,8 +173,11 @@
$virtualURITable['/skins/'] = 'errorFile';
$virtualURITable['/files/'] = 'errorFile';
$virtualURITable['/[a-zA-Z][a-zA-Z0-9]{0,}()'] = 'sysUnnamed';
$virtualURITable['/rest/(*)'] = 'rest-service';
$virtualURITable['/(*)'] = PATH_HTML;
$isRestRequest = false;
// Verify if we need to redirect or stream the file, if G:VirtualURI returns true means we are going to redirect the page
if ( G::virtualURI($_SERVER['REQUEST_URI'], $virtualURITable , $realPath )) {
// review if the file requested belongs to public_html plugin
@@ -205,6 +208,11 @@
die;
}
// if (substr($realPath, 0, 12) === 'rest-service') {
// G::dispatchRestService();
// die;
// }
$requestUriArray = explode("/",$_SERVER['REQUEST_URI']);
if((isset($requestUriArray[1]))&&($requestUriArray[1] == 'skin')) {
@@ -248,15 +256,19 @@
die;
break;
default :
if (substr($realPath, 0, 12) == 'rest-service') {
$isRestRequest = true;
} else {
$realPath = explode('?', $realPath);
$realPath[0] .= strpos(basename($realPath[0]), '.') === false ? '.php' : '';
G::streamFile ( $realPath[0] );
die;
}
}
}
// the request correspond to valid php page, now parse the URI
G::parseURI(getenv("REQUEST_URI"));
G::parseURI(getenv("REQUEST_URI"), $isRestRequest);
// verify if index.html exists
if (!file_exists(PATH_HTML . 'index.html')) { // if not, create it from template
@@ -563,8 +575,12 @@
$isControllerCall = true;
}
}
// var_dump(SYS_SYS);
// var_dump(SYS_TARGET);
// var_dump($isRestRequest);
// die;
if (!$isControllerCall && ! file_exists($phpFile)) {
if (!$isControllerCall && ! file_exists($phpFile) && ! $isRestRequest) {
$_SESSION['phpFileNotFound'] = $_SERVER['REQUEST_URI'];
header("location: /errors/error404.php?url=" . urlencode($_SERVER['REQUEST_URI']));
die;
@@ -630,7 +646,11 @@
$noLoginFolders[] = 'installer';
// This sentence is used when you lost the Session
if ( !in_array(SYS_TARGET, $noLoginFiles) && !in_array(SYS_COLLECTION, $noLoginFolders) && $bWE != true && $collectionPlugin != 'services') {
if (! in_array(SYS_TARGET, $noLoginFiles)
&& ! in_array(SYS_COLLECTION, $noLoginFolders)
&& $bWE != true && $collectionPlugin != 'services'
&& ! $isRestRequest
) {
$bRedirect = true;
if (isset($_GET['sid'])) {
@@ -686,8 +706,9 @@
$controller = new $controllerClass();
$controller->setHttpRequestData($_REQUEST);
$controller->call($controllerAction);
}
else {
} elseif ($isRestRequest) {
G::dispatchRestService(SYS_TARGET);
} else {
require_once $phpFile;
}